diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..2a2b4d88c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +vagrant/.vagrant +.sass-cache +.idea \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..8c96bf7338 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,3 @@ +FROM httpd:2.4 + +COPY . /usr/local/apache2/htdocs/ \ No newline at end of file diff --git a/README.md b/README.md index a9d6092ec9..797698a8f5 100644 --- a/README.md +++ b/README.md @@ -1,64 +1,34 @@ -Here at GitHub, we're no strangers to hosting or sponsoring hackathons. With the growing number of games and game development resources on GitHub, we thought it was about time to throw our very own game jam! +# ScriptFoo -## The Challenge +Welcome to a fantastic world, powered by Javascript and filled with pixels. -You have the entire month of November to create a **web-based** game *loosely* built around one or more of the following themes: +As you meet new characters, the mysteries of the underlying logical force will be slowly explained. -* forking (or forks) -* branching (or branches) -* cloning (or clones) -* pushing -* pulling +Test out your newly granted powers and manipulate your way through the adventure. -What do we mean by **loosely** based on these concepts? We literally mean, *loosely* based. Some examples might be a FPS where you throw forks at water balloons, an educational game about DNA cloning, or perhaps a platformer where you push and pull objects. +![ScriptFoo](http://scriptfoo.github.com/game-off-2012/screenshot.png "ScriptFoo") -Your game. Your rules. You can participate as an individual or as a team. You're encouraged to use open source libraries, frameworks, graphics, and sounds. +## Open Source Projects -## Prizes +* Crafty.js +* Backbone.js +* RequireJS +* jQuery +* mondernizr +* Hogan.js -We have 5 shiny new iPads with Retina displays (64GB wifi models) to give to our winners (or Apple Store Credit equivalent). Runners up will receive GitHub swag of their choice ($100 credit for the [GitHub Shop](http://shop.github.com/)). If you have a team submission, we'll give you Apple Store credit equal to the value of the iPad. You can split it with your teammates as appropriate. +## Roadmap -All of the winners and runners up will be showcased on our blog. +* New quests (lessons) +* Add rabbit quest +* Add maze puzzle +* Add more puzzles and mazes +* New scenes +* New characters +* Sound effects - +### Contributors -### Everyone's a winner! - -All participants will receive a limited edition [Coderwall](http://www.coderwall.com) badge as shown above. Winners and runners up will also get their own special version of it. - -## Judging - -We have a number of awesome judges who graciously volunteered to take a look at all the entries! - -* [David Czarnecki](http://twitter.com/CzarneckiD), Lead Engineer at Agora Games -* [Eric Preisz](https://twitter.com/epreisz), CEO of GarageGames -* [Matt Hackett](https://twitter.com/#!/richtaur), Co-founder of Lost Decade Games -* [Lee Reilly](http://twitter.com/leereilly), Gamer Dad and Software Developer at GitHub -* [Romana Ramzan](https://twitter.com/Manak/), Denki's Player Champion. PhD Researcher. Organiser of Scottish Game Jam. - -## Rules - -* To qualify for entry as an **individual** you must fork the [github/game-off-2012](https://github.com/github/game-off-2012) repository to your individual account -* To qualify for entry as a **team** you must fork the [github/game-off-2012](https://github.com/github/game-off-2012) to a [free organization account](https://github.com/settings/organizations) -* All entries must be web-based i.e. playable in a browser. HTML5, WebGL, Unity, Torque 3D, Node JS, Flash is all possible - just be sure the source is made available on your fork. -* You must be over the age of 13 - -## Instructions - -* If you don't already have a GitHub account, [sign up now](https://github.com/signup/free) - it's free! -* Fork the [github/game-off-2012](https://github.com/github/game-off-2012) repository to your individual account (or to a free organization account) -* Be sure to follow @github on Twitter for updates -* Make sure your code is pushed to the master branch of before Dec 1st! -* Make sure you have a README file with a brief description, what open source projects (if any) you used, and a screenshot. -* Your repo should have a brief description and a URL where the game is playable entered into the fields shown below (this will make our judging process easier): - -![](https://img.skitch.com/20121010-x2ecpu95fi91us6hbfehg2dgit.png) - -Winners will be announced before Christmas :santa: - -# Comments / Questions / Help - -* New to Git, GitHub, and/or version control? Check out our [help documentation](https://help.github.com/) to get started! -* Questions about Git/GitHub? Please email support@github.com and be sure to include 'GitHub Game Off' in the subject. -* Questions specific to the GitHub Game Off? Please [create an issue](https://github.com/github/game-off-2012/issues/new). That will be the offical FAQ. -* The official Twitter hashtag is [#ggo12](https://twitter.com/search/realtime?q=%23ggo12). \ No newline at end of file +* Lorenzo Pisani [@zeelot3k](http://twitter.com/zeelot3k) | [zeelot3k.com](http://zeelot3k.com) +* LaTorri Lindsay [@latorril](http://twitter.com/latorril) | [latorrilindsay.com](http://latorrilindsay.com) +* M. 'Hoke' Hokanson [@h0ke](http://twitter.com/h0ke) | [h0ke.com](http://h0ke.com) \ No newline at end of file diff --git a/SpritesheetGeneration.md b/SpritesheetGeneration.md new file mode 100644 index 0000000000..e6ef65a0e7 --- /dev/null +++ b/SpritesheetGeneration.md @@ -0,0 +1 @@ +montage *.png -mode concatenate -geometry "250x60>+0+0" -tile x1 -background none Sheet.png \ No newline at end of file diff --git a/apple-touch-icon-114x114-precomposed.png b/apple-touch-icon-114x114-precomposed.png new file mode 100644 index 0000000000..f47341bd36 Binary files /dev/null and b/apple-touch-icon-114x114-precomposed.png differ diff --git a/apple-touch-icon-144x144-precomposed.png b/apple-touch-icon-144x144-precomposed.png new file mode 100644 index 0000000000..8f7f798be0 Binary files /dev/null and b/apple-touch-icon-144x144-precomposed.png differ diff --git a/apple-touch-icon-57x57-precomposed.png b/apple-touch-icon-57x57-precomposed.png new file mode 100644 index 0000000000..bbcc50dda2 Binary files /dev/null and b/apple-touch-icon-57x57-precomposed.png differ diff --git a/apple-touch-icon-72x72-precomposed.png b/apple-touch-icon-72x72-precomposed.png new file mode 100644 index 0000000000..c0ff62331e Binary files /dev/null and b/apple-touch-icon-72x72-precomposed.png differ diff --git a/apple-touch-icon-precomposed.png b/apple-touch-icon-precomposed.png new file mode 100644 index 0000000000..bbcc50dda2 Binary files /dev/null and b/apple-touch-icon-precomposed.png differ diff --git a/apple-touch-icon.png b/apple-touch-icon.png new file mode 100644 index 0000000000..bbcc50dda2 Binary files /dev/null and b/apple-touch-icon.png differ diff --git a/config/compass.rb b/config/compass.rb new file mode 100644 index 0000000000..a2c2620935 --- /dev/null +++ b/config/compass.rb @@ -0,0 +1,6 @@ +css_dir = "css" +sass_dir = "scss" +output_style = :expanded +images_dir = "images" +relative_assets = true +line_comments = true \ No newline at end of file diff --git a/css/styles.css b/css/styles.css new file mode 100644 index 0000000000..84416766d2 --- /dev/null +++ b/css/styles.css @@ -0,0 +1,1096 @@ +/** + * A lot of inspiration came from the SMACSS book: https://smacss.com + */ +/* normalize.css v2.0.1 | MIT License | git.io/normalize */ +/* ========================================================================== + HTML5 display definitions + ========================================================================== */ +/* + * Corrects `block` display not defined in IE 8/9. + */ +/* line 21, ../scss/_normalize.scss */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section, +summary { + display: block; +} + +/* + * Corrects `inline-block` display not defined in IE 8/9. + */ +/* line 31, ../scss/_normalize.scss */ +audio, +canvas, +video { + display: inline-block; +} + +/* + * Prevents modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ +/* line 40, ../scss/_normalize.scss */ +audio:not([controls]) { + display: none; + height: 0; +} + +/* + * Addresses styling for `hidden` attribute not present in IE 8/9. + */ +/* line 49, ../scss/_normalize.scss */ +[hidden] { + display: none; +} + +/* ========================================================================== + Base + ========================================================================== */ +/* + * 1. Sets default font family to sans-serif. + * 2. Prevents iOS text size adjust after orientation change, without disabling + * user zoom. + */ +/* line 63, ../scss/_normalize.scss */ +html { + font-family: sans-serif; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ + -ms-text-size-adjust: 100%; + /* 2 */ +} + +/* + * Removes default margin. + */ +/* line 73, ../scss/_normalize.scss */ +body { + margin: 0; +} + +/* ========================================================================== + Links + ========================================================================== */ +/* + * Addresses `outline` inconsistency between Chrome and other browsers. + */ +/* line 85, ../scss/_normalize.scss */ +a:focus { + outline: thin dotted; +} + +/* + * Improves readability when focused and also mouse hovered in all browsers. + */ +/* line 94, ../scss/_normalize.scss */ +a:active, +a:hover { + outline: 0; +} + +/* ========================================================================== + Typography + ========================================================================== */ +/* + * Addresses `h1` font sizes within `section` and `article` in Firefox 4+, + * Safari 5, and Chrome. + */ +/* line 107, ../scss/_normalize.scss */ +h1 { + font-size: 2em; +} + +/* + * Addresses styling not present in IE 8/9, Safari 5, and Chrome. + */ +/* line 115, ../scss/_normalize.scss */ +abbr[title] { + border-bottom: 1px dotted; +} + +/* + * Addresses style set to `bolder` in Firefox 4+, Safari 5, and Chrome. + */ +/* line 124, ../scss/_normalize.scss */ +b, +strong { + font-weight: bold; +} + +/* + * Addresses styling not present in Safari 5 and Chrome. + */ +/* line 132, ../scss/_normalize.scss */ +dfn { + font-style: italic; +} + +/* + * Addresses styling not present in IE 8/9. + */ +/* line 140, ../scss/_normalize.scss */ +mark { + background: #ff0; + color: #000; +} + +/* + * Corrects font family set oddly in Safari 5 and Chrome. + */ +/* line 153, ../scss/_normalize.scss */ +code, +kbd, +pre, +samp { + font-family: monospace, serif; + font-size: 1em; +} + +/* + * Improves readability of pre-formatted text in all browsers. + */ +/* line 162, ../scss/_normalize.scss */ +pre { + white-space: pre; + white-space: pre-wrap; + word-wrap: break-word; +} + +/* + * Sets consistent quote types. + */ +/* line 172, ../scss/_normalize.scss */ +q { + quotes: "\201C" "\201D" "\2018" "\2019"; +} + +/* + * Addresses inconsistent and variable font size in all browsers. + */ +/* line 180, ../scss/_normalize.scss */ +small { + font-size: 80%; +} + +/* + * Prevents `sub` and `sup` affecting `line-height` in all browsers. + */ +/* line 189, ../scss/_normalize.scss */ +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +/* line 196, ../scss/_normalize.scss */ +sup { + top: -0.5em; +} + +/* line 200, ../scss/_normalize.scss */ +sub { + bottom: -0.25em; +} + +/* ========================================================================== + Embedded content + ========================================================================== */ +/* + * Removes border when inside `a` element in IE 8/9. + */ +/* line 212, ../scss/_normalize.scss */ +img { + border: 0; +} + +/* + * Corrects overflow displayed oddly in IE 9. + */ +/* line 220, ../scss/_normalize.scss */ +svg:not(:root) { + overflow: hidden; +} + +/* ========================================================================== + Figures + ========================================================================== */ +/* + * Addresses margin not present in IE 8/9 and Safari 5. + */ +/* line 232, ../scss/_normalize.scss */ +figure { + margin: 0; +} + +/* ========================================================================== + Forms + ========================================================================== */ +/* + * Define consistent border, margin, and padding. + */ +/* line 244, ../scss/_normalize.scss */ +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/* + * 1. Corrects color not being inherited in IE 8/9. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ +/* line 255, ../scss/_normalize.scss */ +legend { + border: 0; + /* 1 */ + padding: 0; + /* 2 */ +} + +/* + * 1. Corrects font family not being inherited in all browsers. + * 2. Corrects font size not being inherited in all browsers. + * 3. Addresses margins set differently in Firefox 4+, Safari 5, and Chrome + */ +/* line 269, ../scss/_normalize.scss */ +button, +input, +select, +textarea { + font-family: inherit; + /* 1 */ + font-size: 100%; + /* 2 */ + margin: 0; + /* 3 */ +} + +/* + * Addresses Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ +/* line 281, ../scss/_normalize.scss */ +button, +input { + line-height: normal; +} + +/* + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Corrects inability to style clickable `input` types in iOS. + * 3. Improves usability and consistency of cursor style between image-type + * `input` and others. + */ +/* line 296, ../scss/_normalize.scss */ +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; + /* 2 */ + cursor: pointer; + /* 3 */ +} + +/* + * Re-set default cursor for disabled elements. + */ +/* line 306, ../scss/_normalize.scss */ +button[disabled], +input[disabled] { + cursor: default; +} + +/* + * 1. Addresses box sizing set to `content-box` in IE 8/9. + * 2. Removes excess padding in IE 8/9. + */ +/* line 316, ../scss/_normalize.scss */ +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; + /* 1 */ + padding: 0; + /* 2 */ +} + +/* + * 1. Addresses `appearance` set to `searchfield` in Safari 5 and Chrome. + * 2. Addresses `box-sizing` set to `border-box` in Safari 5 and Chrome + * (include `-moz` to future-proof). + */ +/* line 327, ../scss/_normalize.scss */ +input[type="search"] { + -webkit-appearance: textfield; + /* 1 */ + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; + /* 2 */ + box-sizing: content-box; +} + +/* + * Removes inner padding and search cancel button in Safari 5 and Chrome + * on OS X. + */ +/* line 340, ../scss/_normalize.scss */ +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* + * Removes inner padding and border in Firefox 4+. + */ +/* line 349, ../scss/_normalize.scss */ +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +/* + * 1. Removes default vertical scrollbar in IE 8/9. + * 2. Improves readability and alignment in all browsers. + */ +/* line 359, ../scss/_normalize.scss */ +textarea { + overflow: auto; + /* 1 */ + vertical-align: top; + /* 2 */ +} + +/* ========================================================================== + Tables + ========================================================================== */ +/* + * Remove most spacing between table cells. + */ +/* line 372, ../scss/_normalize.scss */ +table { + border-collapse: collapse; + border-spacing: 0; +} + +/** + * Colors by name. + * These colors are not to be used outside of the theme file. They are basically + * our color palette. + */ +/* line 23, ../scss/_theme.scss */ +.widget-action-messages .action-message { + font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; +} + +/* line 27, ../scss/_theme.scss */ +body { + background: #282828; +} + +/* line 31, ../scss/_theme.scss */ +.l-page:before { + background: url(../images/logo.png) center no-repeat; +} + +/* line 35, ../scss/_theme.scss */ +.l-game { + -moz-box-shadow: rgba(0, 0, 0, 0.6) 0 0 15px 2px; + -webkit-box-shadow: rgba(0, 0, 0, 0.6) 0 0 15px 2px; + -o-box-shadow: rgba(0, 0, 0, 0.6) 0 0 15px 2px; + box-shadow: rgba(0, 0, 0, 0.6) 0 0 15px 2px; + border: 2px solid #383838; +} + +/* line 41, ../scss/_theme.scss */ +.l-game-toolbar { + color: white; + background: #383838; + border-top: 1px solid #484848; + border-bottom: 1px solid #484848; +} + +/* line 49, ../scss/_theme.scss */ +.l-toolbar-runes li { + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + -o-border-radius: 3px; + -ms-border-radius: 3px; + -khtml-border-radius: 3px; + border-radius: 3px; + -moz-box-shadow: #282828 0 0 4px 2px; + -webkit-box-shadow: #282828 0 0 4px 2px; + -o-box-shadow: #282828 0 0 4px 2px; + box-shadow: #282828 0 0 4px 2px; + border: 1px solid #484848; + background: #383838; +} +/* line 56, ../scss/_theme.scss */ +.l-toolbar-runes li:hover { + -moz-box-shadow: #484848 0 0 7px 2px; + -webkit-box-shadow: #484848 0 0 7px 2px; + -o-box-shadow: #484848 0 0 7px 2px; + box-shadow: #484848 0 0 7px 2px; + border: 1px solid #a2a2a2; +} + +/* line 62, ../scss/_theme.scss */ +.widget-inventory { + background: #383838; + border-left: 1px solid #484848; +} +/* line 66, ../scss/_theme.scss */ +.widget-inventory:before { + content: ''; + width: 34px; + height: 29px; + position: absolute; + top: 10px; + left: 50%; + margin-left: -17px; + background: url("../images/sprites/Backpacks.png") no-repeat; +} +/* line 77, ../scss/_theme.scss */ +.widget-inventory li { + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + -o-border-radius: 3px; + -ms-border-radius: 3px; + -khtml-border-radius: 3px; + border-radius: 3px; + -moz-box-shadow: #282828 0 0 4px 2px; + -webkit-box-shadow: #282828 0 0 4px 2px; + -o-box-shadow: #282828 0 0 4px 2px; + box-shadow: #282828 0 0 4px 2px; + border: 1px solid #484848; + background: #383838; +} +/* line 84, ../scss/_theme.scss */ +.widget-inventory li:hover { + -moz-box-shadow: #484848 0 0 7px 2px; + -webkit-box-shadow: #484848 0 0 7px 2px; + -o-box-shadow: #484848 0 0 7px 2px; + box-shadow: #484848 0 0 7px 2px; + border: 1px solid #a2a2a2; +} + +/* line 90, ../scss/_theme.scss */ +.l-button { + text-shadow: 0px 1px 0px rgba(0, 0, 0, 0.2); + font-family: 'OpenSansLight', "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: normal; + list-style: none; + display: inline; + color: white; + font-size: 14px; + background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #93bd20), color-stop(100%, #659e10)); + background: -webkit-linear-gradient(#93bd20, #659e10); + background: -moz-linear-gradient(#93bd20, #659e10); + background: -o-linear-gradient(#93bd20, #659e10); + background: -ms-linear-gradient(#93bd20, #659e10); + background: linear-gradient(#93bd20, #659e10); + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + -o-border-radius: 2px; + -ms-border-radius: 2px; + -khtml-border-radius: 2px; + border-radius: 2px; + -moz-box-shadow: rgba(255, 255, 255, 0.3) 0px 1px 0px 0px inset, rgba(0, 0, 0, 0.7) 0px 3px 7px; + -webkit-box-shadow: rgba(255, 255, 255, 0.3) 0px 1px 0px 0px inset, rgba(0, 0, 0, 0.7) 0px 3px 7px; + -o-box-shadow: rgba(255, 255, 255, 0.3) 0px 1px 0px 0px inset, rgba(0, 0, 0, 0.7) 0px 3px 7px; + box-shadow: rgba(255, 255, 255, 0.3) 0px 1px 0px 0px inset, rgba(0, 0, 0, 0.7) 0px 3px 7px; + color: white; + border: 1px solid #5d910b; + background-color: #93bd20; + font-size: 14px; + text-align: center; + font-weight: 400; + text-decoration: none; +} +/* line 113, ../scss/_theme.scss */ +.l-button:hover { + background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #749619), color-stop(100%, #527f0e)); + background: -webkit-linear-gradient(#749619, #527f0e); + background: -moz-linear-gradient(#749619, #527f0e); + background: -o-linear-gradient(#749619, #527f0e); + background: -ms-linear-gradient(#749619, #527f0e); + background: linear-gradient(#749619, #527f0e); + -moz-box-shadow: rgba(0, 0, 0, 0.3) 0px 1px 1px 0px inset, transparent 0px 1px 0px; + -webkit-box-shadow: rgba(0, 0, 0, 0.3) 0px 1px 1px 0px inset, transparent 0px 1px 0px; + -o-box-shadow: rgba(0, 0, 0, 0.3) 0px 1px 1px 0px inset, transparent 0px 1px 0px; + box-shadow: rgba(0, 0, 0, 0.3) 0px 1px 1px 0px inset, transparent 0px 1px 0px; + background-color: #659e10; + border: 1px solid #527f0e; +} + +/** + * Navigation Related Theme Styles + */ +/* line 125, ../scss/_theme.scss */ +.l-nav-button { + text-shadow: 0px 1px 0px rgba(0, 0, 0, 0.2); + font-family: 'OpenSansLight', "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: normal; + list-style: none; + display: inline; + color: white; + font-size: 14px; +} +/* line 136, ../scss/_theme.scss */ +.l-nav-button a { + background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #93bd20), color-stop(100%, #659e10)); + background: -webkit-linear-gradient(#93bd20, #659e10); + background: -moz-linear-gradient(#93bd20, #659e10); + background: -o-linear-gradient(#93bd20, #659e10); + background: -ms-linear-gradient(#93bd20, #659e10); + background: linear-gradient(#93bd20, #659e10); + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + -o-border-radius: 2px; + -ms-border-radius: 2px; + -khtml-border-radius: 2px; + border-radius: 2px; + -moz-box-shadow: rgba(255, 255, 255, 0.3) 0px 1px 0px 0px inset, rgba(0, 0, 0, 0.7) 0px 3px 7px; + -webkit-box-shadow: rgba(255, 255, 255, 0.3) 0px 1px 0px 0px inset, rgba(0, 0, 0, 0.7) 0px 3px 7px; + -o-box-shadow: rgba(255, 255, 255, 0.3) 0px 1px 0px 0px inset, rgba(0, 0, 0, 0.7) 0px 3px 7px; + box-shadow: rgba(255, 255, 255, 0.3) 0px 1px 0px 0px inset, rgba(0, 0, 0, 0.7) 0px 3px 7px; + color: white; + border: 1px solid #5d910b; + background-color: #93bd20; + font-size: 14px; + text-align: center; + font-weight: 400; + text-decoration: none; +} +/* line 149, ../scss/_theme.scss */ +.l-nav-button a:hover { + background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #749619), color-stop(100%, #527f0e)); + background: -webkit-linear-gradient(#749619, #527f0e); + background: -moz-linear-gradient(#749619, #527f0e); + background: -o-linear-gradient(#749619, #527f0e); + background: -ms-linear-gradient(#749619, #527f0e); + background: linear-gradient(#749619, #527f0e); + -moz-box-shadow: rgba(0, 0, 0, 0.3) 0px 1px 1px 0px inset, transparent 0px 1px 0px; + -webkit-box-shadow: rgba(0, 0, 0, 0.3) 0px 1px 1px 0px inset, transparent 0px 1px 0px; + -o-box-shadow: rgba(0, 0, 0, 0.3) 0px 1px 1px 0px inset, transparent 0px 1px 0px; + box-shadow: rgba(0, 0, 0, 0.3) 0px 1px 1px 0px inset, transparent 0px 1px 0px; + background-color: #659e10; + border: 1px solid #527f0e; +} + +/* + * Clearfix: contain floats + * + * For modern browsers + * 1. The space content is one way to avoid an Opera bug when the + * `contenteditable` attribute is included anywhere else in the document. + * Otherwise it causes space to appear at the top and bottom of elements + * that receive the `clearfix` class. + * 2. The use of `table` rather than `block` is only necessary if using + * `:before` to contain the top-margins of child elements. + */ +/* + * For IE 6/7 only + * Include this rule to trigger hasLayout and contain floats. + */ +/* line 5, ../scss/_base.scss */ +ul { + padding: 0; + margin: 0; +} + +/* line 1, ../scss/_layout.scss */ +.l-page:before { + content: " "; + display: block; + position: absolute; + top: 0; + left: 0; + right: 0; + width: 100%; + height: 80px; +} + +/* line 14, ../scss/_layout.scss */ +.l-header, .l-footer { + width: 950px; + margin: 0 auto; + overflow: hidden; + *zoom: 1; + height: 80px; +} +/* line 19, ../scss/_layout.scss */ +.l-header nav, .l-footer nav { + display: inline; + float: left; + margin-right: 0; + width: 950px; +} +/* line 147, ../../../../usr/lib/ruby/gems/1.9.1/gems/compass-0.11.5/frameworks/blueprint/stylesheets/blueprint/_grid.scss */ +* html .l-header nav, * html .l-footer nav { + overflow-x: hidden; +} + +/* line 24, ../scss/_layout.scss */ +.l-header { + position: relative; +} + +/* line 28, ../scss/_layout.scss */ +.l-game { + width: 950px; + margin: 0 auto; + overflow: hidden; + *zoom: 1; +} +/* line 31, ../scss/_layout.scss */ +.l-game .l-content-wrapper { + display: inline; + float: left; + margin-right: 0; + width: 950px; +} +/* line 147, ../../../../usr/lib/ruby/gems/1.9.1/gems/compass-0.11.5/frameworks/blueprint/stylesheets/blueprint/_grid.scss */ +* html .l-game .l-content-wrapper { + overflow-x: hidden; +} +/* line 35, ../scss/_layout.scss */ +.l-game .spell-editor { + position: relative; +} + +/* line 40, ../scss/_layout.scss */ +.dialog { + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + -o-border-radius: 5px; + -ms-border-radius: 5px; + -khtml-border-radius: 5px; + border-radius: 5px; + width: 860px; + background: #E8E6DC; + min-height: 100px; + position: absolute; + bottom: 162px; + margin-left: 20px; + z-index: 2; + border: 5px solid #5d910b; + display: none; + padding: 0 20px; +} + +/* line 5, ../scss/module/_navigation.scss */ +.module-horizontal-navigation, .l-nav { + margin: 0; + padding: 0; + border: 0; + overflow: hidden; + *zoom: 1; +} +/* line 60, ../../../../usr/lib/ruby/gems/1.9.1/gems/compass-0.11.5/frameworks/compass/stylesheets/compass/typography/lists/_horizontal-list.scss */ +.module-horizontal-navigation li, .l-nav li { + list-style-image: none; + list-style-type: none; + margin-left: 0px; + white-space: nowrap; + display: inline; + float: left; + padding-left: 4px; + padding-right: 4px; +} +/* line 48, ../../../../usr/lib/ruby/gems/1.9.1/gems/compass-0.11.5/frameworks/compass/stylesheets/compass/typography/lists/_horizontal-list.scss */ +.module-horizontal-navigation li:first-child, .l-nav li:first-child, .module-horizontal-navigation li.first, .l-nav li.first { + padding-left: 0; +} +/* line 49, ../../../../usr/lib/ruby/gems/1.9.1/gems/compass-0.11.5/frameworks/compass/stylesheets/compass/typography/lists/_horizontal-list.scss */ +.module-horizontal-navigation li:last-child, .l-nav li:last-child { + padding-right: 0; +} +/* line 50, ../../../../usr/lib/ruby/gems/1.9.1/gems/compass-0.11.5/frameworks/compass/stylesheets/compass/typography/lists/_horizontal-list.scss */ +.module-horizontal-navigation li.last, .l-nav li.last { + padding-right: 0; +} + +/* line 11, ../scss/module/_navigation.scss */ +.l-nav { + margin-top: 6px; +} + +/* line 17, ../scss/module/_navigation.scss */ +.l-nav-button { + line-height: 50px; +} +/* line 22, ../scss/module/_navigation.scss */ +.l-nav-button a { + padding: 10px 12px; + margin-top: 6px; + line-height: 14px; + display: inline-block; +} + +/* line 1, ../scss/module/_forms.scss */ +.l-button { + margin: 8px; + padding: 5px 15px; +} + +/* line 2, ../scss/module/_gameComponents.scss */ +#cr-stage:before { + content: ' '; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: block; + z-index: 1000; +} +/* line 13, ../scss/module/_gameComponents.scss */ +#cr-stage.day { + background-color: #A5B89B; +} +/* line 16, ../scss/module/_gameComponents.scss */ +#cr-stage.day:before { + background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, rgba(177, 212, 198, 0.8)), color-stop(50%, rgba(177, 212, 198, 0)), color-stop(100%, rgba(177, 212, 198, 0))); + background-image: -webkit-linear-gradient(rgba(177, 212, 198, 0.8), rgba(177, 212, 198, 0), rgba(177, 212, 198, 0)); + background-image: -moz-linear-gradient(rgba(177, 212, 198, 0.8), rgba(177, 212, 198, 0), rgba(177, 212, 198, 0)); + background-image: -o-linear-gradient(rgba(177, 212, 198, 0.8), rgba(177, 212, 198, 0), rgba(177, 212, 198, 0)); + background-image: -ms-linear-gradient(rgba(177, 212, 198, 0.8), rgba(177, 212, 198, 0), rgba(177, 212, 198, 0)); + background-image: linear-gradient(rgba(177, 212, 198, 0.8), rgba(177, 212, 198, 0), rgba(177, 212, 198, 0)); +} +/* line 21, ../scss/module/_gameComponents.scss */ +#cr-stage.dayFoggy { + background-color: #889A8E; +} +/* line 24, ../scss/module/_gameComponents.scss */ +#cr-stage.dayFoggy:before { + background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, rgba(247, 237, 255, 0.8)), color-stop(100%, rgba(247, 237, 255, 0.3))); + background-image: -webkit-linear-gradient(rgba(247, 237, 255, 0.8), rgba(247, 237, 255, 0.3)); + background-image: -moz-linear-gradient(rgba(247, 237, 255, 0.8), rgba(247, 237, 255, 0.3)); + background-image: -o-linear-gradient(rgba(247, 237, 255, 0.8), rgba(247, 237, 255, 0.3)); + background-image: -ms-linear-gradient(rgba(247, 237, 255, 0.8), rgba(247, 237, 255, 0.3)); + background-image: linear-gradient(rgba(247, 237, 255, 0.8), rgba(247, 237, 255, 0.3)); +} +/* line 29, ../scss/module/_gameComponents.scss */ +#cr-stage.evening { + background-color: #806363; +} +/* line 32, ../scss/module/_gameComponents.scss */ +#cr-stage.evening:before { + background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, rgba(184, 212, 177, 0.8)), color-stop(50%, rgba(184, 212, 177, 0)), color-stop(100%, rgba(184, 212, 177, 0))); + background-image: -webkit-linear-gradient(rgba(184, 212, 177, 0.8), rgba(184, 212, 177, 0), rgba(184, 212, 177, 0)); + background-image: -moz-linear-gradient(rgba(184, 212, 177, 0.8), rgba(184, 212, 177, 0), rgba(184, 212, 177, 0)); + background-image: -o-linear-gradient(rgba(184, 212, 177, 0.8), rgba(184, 212, 177, 0), rgba(184, 212, 177, 0)); + background-image: -ms-linear-gradient(rgba(184, 212, 177, 0.8), rgba(184, 212, 177, 0), rgba(184, 212, 177, 0)); + background-image: linear-gradient(rgba(184, 212, 177, 0.8), rgba(184, 212, 177, 0), rgba(184, 212, 177, 0)); +} +/* line 37, ../scss/module/_gameComponents.scss */ +#cr-stage.night { + background-color: #63807B; +} +/* line 40, ../scss/module/_gameComponents.scss */ +#cr-stage.night:before { + background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, rgba(30, 30, 42, 0.8)), color-stop(50%, rgba(30, 30, 42, 0)), color-stop(100%, rgba(30, 30, 42, 0))); + background-image: -webkit-linear-gradient(rgba(30, 30, 42, 0.8), rgba(30, 30, 42, 0), rgba(30, 30, 42, 0)); + background-image: -moz-linear-gradient(rgba(30, 30, 42, 0.8), rgba(30, 30, 42, 0), rgba(30, 30, 42, 0)); + background-image: -o-linear-gradient(rgba(30, 30, 42, 0.8), rgba(30, 30, 42, 0), rgba(30, 30, 42, 0)); + background-image: -ms-linear-gradient(rgba(30, 30, 42, 0.8), rgba(30, 30, 42, 0), rgba(30, 30, 42, 0)); + background-image: linear-gradient(rgba(30, 30, 42, 0.8), rgba(30, 30, 42, 0), rgba(30, 30, 42, 0)); +} + +/* line 46, ../scss/module/_gameComponents.scss */ +.fps { + position: absolute; + z-index: 10000; + top: 10px; + left: 10px; + font-weight: 800; + font-size: 2em; + color: white; +} + +/* line 60, ../scss/module/_gameComponents.scss */ +.l-game-wrapper { + position: relative; +} + +/* line 64, ../scss/module/_gameComponents.scss */ +.l-game-toolbar { + height: 45px; +} +/* line 68, ../scss/module/_gameComponents.scss */ +.l-game-toolbar .cast { + float: left; +} + +/* line 73, ../scss/module/_gameComponents.scss */ +.l-toolbar-runes { + float: left; +} +/* line 78, ../scss/module/_gameComponents.scss */ +.l-toolbar-runes ul { + list-style: none; + padding: 7px 7px; +} +/* line 83, ../scss/module/_gameComponents.scss */ +.l-toolbar-runes li { + height: 30px; + width: 30px; + margin: 0 10px 0 0; + padding: none; + float: left; + position: relative; +} +/* line 91, ../scss/module/_gameComponents.scss */ +.l-toolbar-runes li:before { + content: ''; + display: block; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + margin: auto; +} +/* line 104, ../scss/module/_gameComponents.scss */ +.l-toolbar-runes .item-slot-gold-rune:before { + height: 6px; + width: 6px; + background: url("../images/sprites/Runes.png") no-repeat -6px 0; +} + +/* line 112, ../scss/module/_gameComponents.scss */ +.l-toolbar-inventory { + display: block; + float: right; + height: 45px; + width: 45px; +} +/* line 118, ../scss/module/_gameComponents.scss */ +.l-toolbar-inventory:before { + content: ''; + display: block; + width: 39px; + height: 100%; + background: url("../images/sprites/Backpacks.png") no-repeat -80px 10px; +} +/* line 126, ../scss/module/_gameComponents.scss */ +.l-toolbar-inventory.active:before { + width: 37px; + background-position: -40px 3px; +} + +/* line 133, ../scss/module/_gameComponents.scss */ +.widget-inventory { + -moz-transition-property: right; + -webkit-transition-property: right; + -o-transition-property: right; + transition-property: right; + -moz-transition-duration: 0.5s; + -webkit-transition-duration: 0.5s; + -o-transition-duration: 0.5s; + transition-duration: 0.5s; + -moz-transition-timing-function: ease; + -webkit-transition-timing-function: ease; + -o-transition-timing-function: ease; + transition-timing-function: ease; + width: 240px; + height: 400px; + position: absolute; + top: 0; + right: -240px; + z-index: 10000; +} +/* line 147, ../scss/module/_gameComponents.scss */ +.widget-inventory.open { + right: 0; +} +/* line 151, ../scss/module/_gameComponents.scss */ +.widget-inventory ul { + list-style: none; + padding: 20px; + margin: 35px -10px 0 0; +} +/* line 157, ../scss/module/_gameComponents.scss */ +.widget-inventory li { + height: 30px; + width: 30px; + margin: 0 10px 10px 0; + padding: none; + float: left; + position: relative; +} +/* line 165, ../scss/module/_gameComponents.scss */ +.widget-inventory li:before { + content: ''; + display: block; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + margin: auto; +} +/* line 178, ../scss/module/_gameComponents.scss */ +.widget-inventory .item-slot-gold-rune:before { + height: 6px; + width: 6px; + background: url("../images/sprites/Runes.png") no-repeat -6px 0; +} + +/* line 186, ../scss/module/_gameComponents.scss */ +.widget-game-dialog { + position: absolute; + top: 280px; + z-index: 50; + width: 950px; + height: 110px; +} +/* line 193, ../scss/module/_gameComponents.scss */ +.widget-game-dialog .speaker { + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + -o-border-radius: 10px; + -ms-border-radius: 10px; + -khtml-border-radius: 10px; + border-radius: 10px; + -moz-box-shadow: black 0 0 10px 0; + -webkit-box-shadow: black 0 0 10px 0; + -o-box-shadow: black 0 0 10px 0; + box-shadow: black 0 0 10px 0; + background-image: -webkit-gradient(radial, 50%, 0, 50%, 120, color-stop(0%, rgba(255, 255, 255, 0.7)), color-stop(100%, rgba(0, 0, 0, 0.8))); + background-image: -webkit-radial-gradient(center, rgba(255, 255, 255, 0.7) 0px, rgba(0, 0, 0, 0.8) 120px); + background-image: -moz-radial-gradient(center, rgba(255, 255, 255, 0.7) 0px, rgba(0, 0, 0, 0.8) 120px); + background-image: -o-radial-gradient(center, rgba(255, 255, 255, 0.7) 0px, rgba(0, 0, 0, 0.8) 120px); + background-image: -ms-radial-gradient(center, rgba(255, 255, 255, 0.7) 0px, rgba(0, 0, 0, 0.8) 120px); + background-image: radial-gradient(center, rgba(255, 255, 255, 0.7) 0px, rgba(0, 0, 0, 0.8) 120px); + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + height: 100px; + width: 100px; + float: left; + margin-left: 20px; + border: 1px solid #000; + position: relative; +} +/* line 207, ../scss/module/_gameComponents.scss */ +.widget-game-dialog .image { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + margin: auto; +} +/* line 216, ../scss/module/_gameComponents.scss */ +.widget-game-dialog .text { + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + -o-border-radius: 10px; + -ms-border-radius: 10px; + -khtml-border-radius: 10px; + border-radius: 10px; + -moz-box-shadow: black 0 0 10px 0; + -webkit-box-shadow: black 0 0 10px 0; + -o-box-shadow: black 0 0 10px 0; + box-shadow: black 0 0 10px 0; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + width: 500px; + height: 100px; + padding: 10px; + margin-left: 10px; + float: left; + color: #A6CB92; + background: rgba(0, 0, 0, 0.8); + border: 1px solid #000; +} + +/* line 232, ../scss/module/_gameComponents.scss */ +.widget-action-messages { + position: relative; +} +/* line 235, ../scss/module/_gameComponents.scss */ +.widget-action-messages .action-message { + position: absolute; + width: 900px; + left: -450px; + text-align: center; + filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0); + opacity: 0; + moz-animation-duration: 4s; + -webkit-animation-duration: 4s; + -moz-animation-name: slideOff; + -webkit-animation-name: slideOff; +} +/* line 250, ../scss/module/_gameComponents.scss */ +.widget-action-messages .positive { + text-shadow: 0px 0px 15px #00FF55; + color: #DDFFAA; +} +/* line 254, ../scss/module/_gameComponents.scss */ +.widget-action-messages .negative { + text-shadow: 0px 0px 15px #FF0000; + color: #ffcccc; +} +/* line 258, ../scss/module/_gameComponents.scss */ +.widget-action-messages .method { + text-shadow: 0px 0px 15px #BBBBBB; + color: white; +} + +@-moz-keyframes slideOff { + /* line 265, ../scss/module/_gameComponents.scss */ + from { + filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100); + opacity: 1; + bottom: 0; + } + + /* line 269, ../scss/module/_gameComponents.scss */ + to { + filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0); + opacity: 0; + bottom: 100px; + } +} + +@-webkit-keyframes slideOff { + /* line 276, ../scss/module/_gameComponents.scss */ + from { + filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100); + opacity: 1; + bottom: 0; + } + + /* line 280, ../scss/module/_gameComponents.scss */ + to { + filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0); + opacity: 0; + bottom: 100px; + } +} + +/* line 286, ../scss/module/_gameComponents.scss */ +.spell-editor { + position: relative; + width: 970px; + height: 400px; + font-size: 14px; +} diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000000..ba655161e4 Binary files /dev/null and b/favicon.ico differ diff --git a/git.png b/git.png new file mode 100644 index 0000000000..b539ea8687 Binary files /dev/null and b/git.png differ diff --git a/images/logo.png b/images/logo.png new file mode 100644 index 0000000000..6c2dfcbe0c Binary files /dev/null and b/images/logo.png differ diff --git a/images/nav-bg.gif b/images/nav-bg.gif new file mode 100644 index 0000000000..474396561d Binary files /dev/null and b/images/nav-bg.gif differ diff --git a/images/sprites/Backpacks.png b/images/sprites/Backpacks.png new file mode 100644 index 0000000000..ff7dcf70c5 Binary files /dev/null and b/images/sprites/Backpacks.png differ diff --git a/images/sprites/Bear.png b/images/sprites/Bear.png new file mode 100644 index 0000000000..1346531432 Binary files /dev/null and b/images/sprites/Bear.png differ diff --git a/images/sprites/Bunny.png b/images/sprites/Bunny.png new file mode 100644 index 0000000000..33972c17f3 Binary files /dev/null and b/images/sprites/Bunny.png differ diff --git a/images/sprites/Chests.png b/images/sprites/Chests.png new file mode 100644 index 0000000000..4c0415de66 Binary files /dev/null and b/images/sprites/Chests.png differ diff --git a/images/sprites/Cottages.png b/images/sprites/Cottages.png new file mode 100644 index 0000000000..38971e434b Binary files /dev/null and b/images/sprites/Cottages.png differ diff --git a/images/sprites/Flowers.png b/images/sprites/Flowers.png new file mode 100644 index 0000000000..e3cf3c3e95 Binary files /dev/null and b/images/sprites/Flowers.png differ diff --git a/images/sprites/FooSheet.png b/images/sprites/FooSheet.png new file mode 100644 index 0000000000..1a8a8eedc7 Binary files /dev/null and b/images/sprites/FooSheet.png differ diff --git a/images/sprites/Friar.png b/images/sprites/Friar.png new file mode 100644 index 0000000000..05218d7f83 Binary files /dev/null and b/images/sprites/Friar.png differ diff --git a/images/sprites/Grasses.png b/images/sprites/Grasses.png new file mode 100644 index 0000000000..c7b11c404e Binary files /dev/null and b/images/sprites/Grasses.png differ diff --git a/images/sprites/Info.png b/images/sprites/Info.png new file mode 100644 index 0000000000..8c91d1c622 Binary files /dev/null and b/images/sprites/Info.png differ diff --git a/images/sprites/Ping.png b/images/sprites/Ping.png new file mode 100644 index 0000000000..c4a22cb3d9 Binary files /dev/null and b/images/sprites/Ping.png differ diff --git a/images/sprites/Runes.png b/images/sprites/Runes.png new file mode 100644 index 0000000000..4f6a0c6752 Binary files /dev/null and b/images/sprites/Runes.png differ diff --git a/images/sprites/StarGreen.png b/images/sprites/StarGreen.png new file mode 100644 index 0000000000..4ad4cfe432 Binary files /dev/null and b/images/sprites/StarGreen.png differ diff --git a/images/sprites/Trees.png b/images/sprites/Trees.png new file mode 100644 index 0000000000..59cbcedebd Binary files /dev/null and b/images/sprites/Trees.png differ diff --git a/images/sprites/Villager1.png b/images/sprites/Villager1.png new file mode 100644 index 0000000000..10a1e15bf5 Binary files /dev/null and b/images/sprites/Villager1.png differ diff --git a/images/sprites/Villager2.png b/images/sprites/Villager2.png new file mode 100644 index 0000000000..989fc677c2 Binary files /dev/null and b/images/sprites/Villager2.png differ diff --git a/images/sprites/Weeds.png b/images/sprites/Weeds.png new file mode 100644 index 0000000000..31948f163a Binary files /dev/null and b/images/sprites/Weeds.png differ diff --git a/images/sprites/presprite/Backpacks/Backpack.png b/images/sprites/presprite/Backpacks/Backpack.png new file mode 100644 index 0000000000..0a425c2afd Binary files /dev/null and b/images/sprites/presprite/Backpacks/Backpack.png differ diff --git a/images/sprites/presprite/Backpacks/BackpackDim.png b/images/sprites/presprite/Backpacks/BackpackDim.png new file mode 100644 index 0000000000..47aa0a3d6a Binary files /dev/null and b/images/sprites/presprite/Backpacks/BackpackDim.png differ diff --git a/images/sprites/presprite/Backpacks/BackpackOpen.png b/images/sprites/presprite/Backpacks/BackpackOpen.png new file mode 100644 index 0000000000..4e5f9164c7 Binary files /dev/null and b/images/sprites/presprite/Backpacks/BackpackOpen.png differ diff --git a/images/sprites/presprite/Bar.png b/images/sprites/presprite/Bar.png new file mode 100644 index 0000000000..c07fea705e Binary files /dev/null and b/images/sprites/presprite/Bar.png differ diff --git a/images/sprites/presprite/Bear/BearIdleLeft-000.png b/images/sprites/presprite/Bear/BearIdleLeft-000.png new file mode 100644 index 0000000000..8652d83073 Binary files /dev/null and b/images/sprites/presprite/Bear/BearIdleLeft-000.png differ diff --git a/images/sprites/presprite/Bear/BearIdleLeft-001.png b/images/sprites/presprite/Bear/BearIdleLeft-001.png new file mode 100644 index 0000000000..db7c958fd6 Binary files /dev/null and b/images/sprites/presprite/Bear/BearIdleLeft-001.png differ diff --git a/images/sprites/presprite/Bear/BearIdleLeft-002.png b/images/sprites/presprite/Bear/BearIdleLeft-002.png new file mode 100644 index 0000000000..7cb962621f Binary files /dev/null and b/images/sprites/presprite/Bear/BearIdleLeft-002.png differ diff --git a/images/sprites/presprite/Bear/BearIdleLeft-003.png b/images/sprites/presprite/Bear/BearIdleLeft-003.png new file mode 100644 index 0000000000..d311097ba1 Binary files /dev/null and b/images/sprites/presprite/Bear/BearIdleLeft-003.png differ diff --git a/images/sprites/presprite/Bear/BearIdleRight-000.png b/images/sprites/presprite/Bear/BearIdleRight-000.png new file mode 100644 index 0000000000..0c1ada28f5 Binary files /dev/null and b/images/sprites/presprite/Bear/BearIdleRight-000.png differ diff --git a/images/sprites/presprite/Bear/BearIdleRight-001.png b/images/sprites/presprite/Bear/BearIdleRight-001.png new file mode 100644 index 0000000000..90b8586d28 Binary files /dev/null and b/images/sprites/presprite/Bear/BearIdleRight-001.png differ diff --git a/images/sprites/presprite/Bear/BearIdleRight-002.png b/images/sprites/presprite/Bear/BearIdleRight-002.png new file mode 100644 index 0000000000..15f4a41e93 Binary files /dev/null and b/images/sprites/presprite/Bear/BearIdleRight-002.png differ diff --git a/images/sprites/presprite/Bear/BearIdleRight-003.png b/images/sprites/presprite/Bear/BearIdleRight-003.png new file mode 100644 index 0000000000..389b403b14 Binary files /dev/null and b/images/sprites/presprite/Bear/BearIdleRight-003.png differ diff --git a/images/sprites/presprite/Bear/BearWalkLeft-000.png b/images/sprites/presprite/Bear/BearWalkLeft-000.png new file mode 100644 index 0000000000..8652d83073 Binary files /dev/null and b/images/sprites/presprite/Bear/BearWalkLeft-000.png differ diff --git a/images/sprites/presprite/Bear/BearWalkLeft-001.png b/images/sprites/presprite/Bear/BearWalkLeft-001.png new file mode 100644 index 0000000000..afba96d7f5 Binary files /dev/null and b/images/sprites/presprite/Bear/BearWalkLeft-001.png differ diff --git a/images/sprites/presprite/Bear/BearWalkRight-000.png b/images/sprites/presprite/Bear/BearWalkRight-000.png new file mode 100644 index 0000000000..ad32ae0381 Binary files /dev/null and b/images/sprites/presprite/Bear/BearWalkRight-000.png differ diff --git a/images/sprites/presprite/Bear/BearWalkRight-001.png b/images/sprites/presprite/Bear/BearWalkRight-001.png new file mode 100644 index 0000000000..c07a6f397f Binary files /dev/null and b/images/sprites/presprite/Bear/BearWalkRight-001.png differ diff --git a/images/sprites/presprite/Bunny/BunnyIdleLeft-000.png b/images/sprites/presprite/Bunny/BunnyIdleLeft-000.png new file mode 100644 index 0000000000..e6dff4549a Binary files /dev/null and b/images/sprites/presprite/Bunny/BunnyIdleLeft-000.png differ diff --git a/images/sprites/presprite/Bunny/BunnyIdleLeft-001.png b/images/sprites/presprite/Bunny/BunnyIdleLeft-001.png new file mode 100644 index 0000000000..edc6115e55 Binary files /dev/null and b/images/sprites/presprite/Bunny/BunnyIdleLeft-001.png differ diff --git a/images/sprites/presprite/Bunny/BunnyIdleRight-000.png b/images/sprites/presprite/Bunny/BunnyIdleRight-000.png new file mode 100644 index 0000000000..c1800db0d1 Binary files /dev/null and b/images/sprites/presprite/Bunny/BunnyIdleRight-000.png differ diff --git a/images/sprites/presprite/Bunny/BunnyIdleRight-001.png b/images/sprites/presprite/Bunny/BunnyIdleRight-001.png new file mode 100644 index 0000000000..4275d72ab8 Binary files /dev/null and b/images/sprites/presprite/Bunny/BunnyIdleRight-001.png differ diff --git a/images/sprites/presprite/Bunny/BunnyWalkLeft-000.png b/images/sprites/presprite/Bunny/BunnyWalkLeft-000.png new file mode 100644 index 0000000000..20d47c8286 Binary files /dev/null and b/images/sprites/presprite/Bunny/BunnyWalkLeft-000.png differ diff --git a/images/sprites/presprite/Bunny/BunnyWalkLeft-001.png b/images/sprites/presprite/Bunny/BunnyWalkLeft-001.png new file mode 100644 index 0000000000..e6dff4549a Binary files /dev/null and b/images/sprites/presprite/Bunny/BunnyWalkLeft-001.png differ diff --git a/images/sprites/presprite/Bunny/BunnyWalkRight-000.png b/images/sprites/presprite/Bunny/BunnyWalkRight-000.png new file mode 100644 index 0000000000..d8f731a6df Binary files /dev/null and b/images/sprites/presprite/Bunny/BunnyWalkRight-000.png differ diff --git a/images/sprites/presprite/Bunny/BunnyWalkRight-001.png b/images/sprites/presprite/Bunny/BunnyWalkRight-001.png new file mode 100644 index 0000000000..477e79de31 Binary files /dev/null and b/images/sprites/presprite/Bunny/BunnyWalkRight-001.png differ diff --git a/images/sprites/presprite/BushGreen.png b/images/sprites/presprite/BushGreen.png new file mode 100644 index 0000000000..8f72ddab1a Binary files /dev/null and b/images/sprites/presprite/BushGreen.png differ diff --git a/images/sprites/presprite/Chests/ChestBlue.png b/images/sprites/presprite/Chests/ChestBlue.png new file mode 100644 index 0000000000..9bc151c990 Binary files /dev/null and b/images/sprites/presprite/Chests/ChestBlue.png differ diff --git a/images/sprites/presprite/Chests/ChestRed.png b/images/sprites/presprite/Chests/ChestRed.png new file mode 100644 index 0000000000..362b3979f5 Binary files /dev/null and b/images/sprites/presprite/Chests/ChestRed.png differ diff --git a/images/sprites/presprite/Cottages/CottageBrown.png b/images/sprites/presprite/Cottages/CottageBrown.png new file mode 100644 index 0000000000..02dd99c6f0 Binary files /dev/null and b/images/sprites/presprite/Cottages/CottageBrown.png differ diff --git a/images/sprites/presprite/Cottages/CottageMaroon.png b/images/sprites/presprite/Cottages/CottageMaroon.png new file mode 100644 index 0000000000..a72923cd2e Binary files /dev/null and b/images/sprites/presprite/Cottages/CottageMaroon.png differ diff --git a/images/sprites/presprite/Flowers/FlowerBlue.png b/images/sprites/presprite/Flowers/FlowerBlue.png new file mode 100644 index 0000000000..abb3b3e7e8 Binary files /dev/null and b/images/sprites/presprite/Flowers/FlowerBlue.png differ diff --git a/images/sprites/presprite/Flowers/FlowerPink.png b/images/sprites/presprite/Flowers/FlowerPink.png new file mode 100644 index 0000000000..e590a6a786 Binary files /dev/null and b/images/sprites/presprite/Flowers/FlowerPink.png differ diff --git a/images/sprites/presprite/Foo/Foo.png b/images/sprites/presprite/Foo/Foo.png new file mode 100644 index 0000000000..a857ff7e18 Binary files /dev/null and b/images/sprites/presprite/Foo/Foo.png differ diff --git a/images/sprites/presprite/Foo/FooWalkDown-000.png b/images/sprites/presprite/Foo/FooWalkDown-000.png new file mode 100644 index 0000000000..10cfcce0e6 Binary files /dev/null and b/images/sprites/presprite/Foo/FooWalkDown-000.png differ diff --git a/images/sprites/presprite/Foo/FooWalkDown-001.png b/images/sprites/presprite/Foo/FooWalkDown-001.png new file mode 100644 index 0000000000..7664237264 Binary files /dev/null and b/images/sprites/presprite/Foo/FooWalkDown-001.png differ diff --git a/images/sprites/presprite/Foo/FooWalkLeft-000.png b/images/sprites/presprite/Foo/FooWalkLeft-000.png new file mode 100644 index 0000000000..eb6133bdd2 Binary files /dev/null and b/images/sprites/presprite/Foo/FooWalkLeft-000.png differ diff --git a/images/sprites/presprite/Foo/FooWalkLeft-001.png b/images/sprites/presprite/Foo/FooWalkLeft-001.png new file mode 100644 index 0000000000..3e1d0eb663 Binary files /dev/null and b/images/sprites/presprite/Foo/FooWalkLeft-001.png differ diff --git a/images/sprites/presprite/Foo/FooWalkRight-000.png b/images/sprites/presprite/Foo/FooWalkRight-000.png new file mode 100644 index 0000000000..486ebe600e Binary files /dev/null and b/images/sprites/presprite/Foo/FooWalkRight-000.png differ diff --git a/images/sprites/presprite/Foo/FooWalkRight-001.png b/images/sprites/presprite/Foo/FooWalkRight-001.png new file mode 100644 index 0000000000..13e9cdd8da Binary files /dev/null and b/images/sprites/presprite/Foo/FooWalkRight-001.png differ diff --git a/images/sprites/presprite/Foo/FooWalkUp-000.png b/images/sprites/presprite/Foo/FooWalkUp-000.png new file mode 100644 index 0000000000..80e4d794c6 Binary files /dev/null and b/images/sprites/presprite/Foo/FooWalkUp-000.png differ diff --git a/images/sprites/presprite/Foo/FooWalkUp-001.png b/images/sprites/presprite/Foo/FooWalkUp-001.png new file mode 100644 index 0000000000..a5965ab4f8 Binary files /dev/null and b/images/sprites/presprite/Foo/FooWalkUp-001.png differ diff --git a/images/sprites/presprite/Friar/FriarIdleLeft-000.png b/images/sprites/presprite/Friar/FriarIdleLeft-000.png new file mode 100644 index 0000000000..765b2d46ce Binary files /dev/null and b/images/sprites/presprite/Friar/FriarIdleLeft-000.png differ diff --git a/images/sprites/presprite/Friar/FriarIdleLeft-001.png b/images/sprites/presprite/Friar/FriarIdleLeft-001.png new file mode 100644 index 0000000000..d62c375004 Binary files /dev/null and b/images/sprites/presprite/Friar/FriarIdleLeft-001.png differ diff --git a/images/sprites/presprite/Friar/FriarIdleRight-000.png b/images/sprites/presprite/Friar/FriarIdleRight-000.png new file mode 100644 index 0000000000..88fbba7323 Binary files /dev/null and b/images/sprites/presprite/Friar/FriarIdleRight-000.png differ diff --git a/images/sprites/presprite/Friar/FriarIdleRight-001.png b/images/sprites/presprite/Friar/FriarIdleRight-001.png new file mode 100644 index 0000000000..7613fe3f0f Binary files /dev/null and b/images/sprites/presprite/Friar/FriarIdleRight-001.png differ diff --git a/images/sprites/presprite/Friar/FriarWalkLeft-000.png b/images/sprites/presprite/Friar/FriarWalkLeft-000.png new file mode 100644 index 0000000000..d7686c4e3c Binary files /dev/null and b/images/sprites/presprite/Friar/FriarWalkLeft-000.png differ diff --git a/images/sprites/presprite/Friar/FriarWalkLeft-001.png b/images/sprites/presprite/Friar/FriarWalkLeft-001.png new file mode 100644 index 0000000000..8a6815eea2 Binary files /dev/null and b/images/sprites/presprite/Friar/FriarWalkLeft-001.png differ diff --git a/images/sprites/presprite/Friar/FriarWalkRight-000.png b/images/sprites/presprite/Friar/FriarWalkRight-000.png new file mode 100644 index 0000000000..d8a711a57b Binary files /dev/null and b/images/sprites/presprite/Friar/FriarWalkRight-000.png differ diff --git a/images/sprites/presprite/Friar/FriarWalkRight-001.png b/images/sprites/presprite/Friar/FriarWalkRight-001.png new file mode 100644 index 0000000000..8c64fd24a1 Binary files /dev/null and b/images/sprites/presprite/Friar/FriarWalkRight-001.png differ diff --git a/images/sprites/presprite/Grasses/GrassAreaLarge.png b/images/sprites/presprite/Grasses/GrassAreaLarge.png new file mode 100644 index 0000000000..5c0a285f97 Binary files /dev/null and b/images/sprites/presprite/Grasses/GrassAreaLarge.png differ diff --git a/images/sprites/presprite/Grasses/GrassAreaSmall.png b/images/sprites/presprite/Grasses/GrassAreaSmall.png new file mode 100644 index 0000000000..ee0bbcc864 Binary files /dev/null and b/images/sprites/presprite/Grasses/GrassAreaSmall.png differ diff --git a/images/sprites/presprite/Grasses/GrassAreaTall.png b/images/sprites/presprite/Grasses/GrassAreaTall.png new file mode 100644 index 0000000000..758be62832 Binary files /dev/null and b/images/sprites/presprite/Grasses/GrassAreaTall.png differ diff --git a/images/sprites/presprite/Grasses/Grasses.png b/images/sprites/presprite/Grasses/Grasses.png new file mode 100644 index 0000000000..c7b11c404e Binary files /dev/null and b/images/sprites/presprite/Grasses/Grasses.png differ diff --git a/images/sprites/presprite/Ping/Ping0000.png b/images/sprites/presprite/Ping/Ping0000.png new file mode 100644 index 0000000000..9c4e76e5ca Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0000.png differ diff --git a/images/sprites/presprite/Ping/Ping0001.png b/images/sprites/presprite/Ping/Ping0001.png new file mode 100644 index 0000000000..1f6ab505b9 Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0001.png differ diff --git a/images/sprites/presprite/Ping/Ping0002.png b/images/sprites/presprite/Ping/Ping0002.png new file mode 100644 index 0000000000..55bdecd91b Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0002.png differ diff --git a/images/sprites/presprite/Ping/Ping0003.png b/images/sprites/presprite/Ping/Ping0003.png new file mode 100644 index 0000000000..5579009f0a Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0003.png differ diff --git a/images/sprites/presprite/Ping/Ping0004.png b/images/sprites/presprite/Ping/Ping0004.png new file mode 100644 index 0000000000..d1f4501a44 Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0004.png differ diff --git a/images/sprites/presprite/Ping/Ping0005.png b/images/sprites/presprite/Ping/Ping0005.png new file mode 100644 index 0000000000..c6b6540a9b Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0005.png differ diff --git a/images/sprites/presprite/Ping/Ping0006.png b/images/sprites/presprite/Ping/Ping0006.png new file mode 100644 index 0000000000..3a676a04d2 Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0006.png differ diff --git a/images/sprites/presprite/Ping/Ping0007.png b/images/sprites/presprite/Ping/Ping0007.png new file mode 100644 index 0000000000..22bd363fd8 Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0007.png differ diff --git a/images/sprites/presprite/Ping/Ping0008.png b/images/sprites/presprite/Ping/Ping0008.png new file mode 100644 index 0000000000..f169aed5b0 Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0008.png differ diff --git a/images/sprites/presprite/Ping/Ping0009.png b/images/sprites/presprite/Ping/Ping0009.png new file mode 100644 index 0000000000..42825a0520 Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0009.png differ diff --git a/images/sprites/presprite/Ping/Ping0010.png b/images/sprites/presprite/Ping/Ping0010.png new file mode 100644 index 0000000000..861e6f5201 Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0010.png differ diff --git a/images/sprites/presprite/Ping/Ping0011.png b/images/sprites/presprite/Ping/Ping0011.png new file mode 100644 index 0000000000..efea5b24fc Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0011.png differ diff --git a/images/sprites/presprite/Ping/Ping0012.png b/images/sprites/presprite/Ping/Ping0012.png new file mode 100644 index 0000000000..3433f936cd Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0012.png differ diff --git a/images/sprites/presprite/Ping/Ping0013.png b/images/sprites/presprite/Ping/Ping0013.png new file mode 100644 index 0000000000..6f4af77849 Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0013.png differ diff --git a/images/sprites/presprite/Ping/Ping0014.png b/images/sprites/presprite/Ping/Ping0014.png new file mode 100644 index 0000000000..a2ed117ddc Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0014.png differ diff --git a/images/sprites/presprite/Ping/Ping0015.png b/images/sprites/presprite/Ping/Ping0015.png new file mode 100644 index 0000000000..9d7359ee1c Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0015.png differ diff --git a/images/sprites/presprite/Ping/Ping0016.png b/images/sprites/presprite/Ping/Ping0016.png new file mode 100644 index 0000000000..ba202329fb Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0016.png differ diff --git a/images/sprites/presprite/Ping/Ping0017.png b/images/sprites/presprite/Ping/Ping0017.png new file mode 100644 index 0000000000..0f6187f8c8 Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0017.png differ diff --git a/images/sprites/presprite/Ping/Ping0018.png b/images/sprites/presprite/Ping/Ping0018.png new file mode 100644 index 0000000000..2823b610f6 Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0018.png differ diff --git a/images/sprites/presprite/Ping/Ping0019.png b/images/sprites/presprite/Ping/Ping0019.png new file mode 100644 index 0000000000..194da59343 Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0019.png differ diff --git a/images/sprites/presprite/Ping/Ping0020.png b/images/sprites/presprite/Ping/Ping0020.png new file mode 100644 index 0000000000..4c293d24b5 Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0020.png differ diff --git a/images/sprites/presprite/Ping/Ping0021.png b/images/sprites/presprite/Ping/Ping0021.png new file mode 100644 index 0000000000..7fcee9dc1a Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0021.png differ diff --git a/images/sprites/presprite/Ping/Ping0022.png b/images/sprites/presprite/Ping/Ping0022.png new file mode 100644 index 0000000000..43d3daecad Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0022.png differ diff --git a/images/sprites/presprite/Ping/Ping0023.png b/images/sprites/presprite/Ping/Ping0023.png new file mode 100644 index 0000000000..d77e03aca5 Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0023.png differ diff --git a/images/sprites/presprite/Ping/Ping0024.png b/images/sprites/presprite/Ping/Ping0024.png new file mode 100644 index 0000000000..12f840acd6 Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0024.png differ diff --git a/images/sprites/presprite/Ping/Ping0025.png b/images/sprites/presprite/Ping/Ping0025.png new file mode 100644 index 0000000000..e2137be035 Binary files /dev/null and b/images/sprites/presprite/Ping/Ping0025.png differ diff --git a/images/sprites/presprite/Ping/PingIdle.png b/images/sprites/presprite/Ping/PingIdle.png new file mode 100644 index 0000000000..a8e7f7c60b Binary files /dev/null and b/images/sprites/presprite/Ping/PingIdle.png differ diff --git a/images/sprites/presprite/Runes/RuneBlue.png b/images/sprites/presprite/Runes/RuneBlue.png new file mode 100644 index 0000000000..dcfc2f0c0e Binary files /dev/null and b/images/sprites/presprite/Runes/RuneBlue.png differ diff --git a/images/sprites/presprite/Runes/RuneGold.png b/images/sprites/presprite/Runes/RuneGold.png new file mode 100644 index 0000000000..44e3c63bb4 Binary files /dev/null and b/images/sprites/presprite/Runes/RuneGold.png differ diff --git a/images/sprites/presprite/Runes/RuneGreen.png b/images/sprites/presprite/Runes/RuneGreen.png new file mode 100644 index 0000000000..4a9b15a152 Binary files /dev/null and b/images/sprites/presprite/Runes/RuneGreen.png differ diff --git a/images/sprites/presprite/Runes/RuneRed.png b/images/sprites/presprite/Runes/RuneRed.png new file mode 100644 index 0000000000..de61589dd2 Binary files /dev/null and b/images/sprites/presprite/Runes/RuneRed.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0000.png b/images/sprites/presprite/StarGreen/StarGreen_0000.png new file mode 100644 index 0000000000..e3c8536f3c Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0000.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0001.png b/images/sprites/presprite/StarGreen/StarGreen_0001.png new file mode 100644 index 0000000000..462d4af220 Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0001.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0002.png b/images/sprites/presprite/StarGreen/StarGreen_0002.png new file mode 100644 index 0000000000..5b532a795e Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0002.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0003.png b/images/sprites/presprite/StarGreen/StarGreen_0003.png new file mode 100644 index 0000000000..1da4e1041d Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0003.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0004.png b/images/sprites/presprite/StarGreen/StarGreen_0004.png new file mode 100644 index 0000000000..5ca900e30a Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0004.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0005.png b/images/sprites/presprite/StarGreen/StarGreen_0005.png new file mode 100644 index 0000000000..718d74c8ef Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0005.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0006.png b/images/sprites/presprite/StarGreen/StarGreen_0006.png new file mode 100644 index 0000000000..be703d828e Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0006.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0007.png b/images/sprites/presprite/StarGreen/StarGreen_0007.png new file mode 100644 index 0000000000..b03d13ce3d Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0007.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0008.png b/images/sprites/presprite/StarGreen/StarGreen_0008.png new file mode 100644 index 0000000000..5e95fd9551 Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0008.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0009.png b/images/sprites/presprite/StarGreen/StarGreen_0009.png new file mode 100644 index 0000000000..3395347475 Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0009.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0010.png b/images/sprites/presprite/StarGreen/StarGreen_0010.png new file mode 100644 index 0000000000..8526b8cc5e Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0010.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0011.png b/images/sprites/presprite/StarGreen/StarGreen_0011.png new file mode 100644 index 0000000000..ff5ccaddf2 Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0011.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0012.png b/images/sprites/presprite/StarGreen/StarGreen_0012.png new file mode 100644 index 0000000000..1daab389ab Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0012.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0013.png b/images/sprites/presprite/StarGreen/StarGreen_0013.png new file mode 100644 index 0000000000..a4474a8702 Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0013.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0014.png b/images/sprites/presprite/StarGreen/StarGreen_0014.png new file mode 100644 index 0000000000..f1f08fb2bf Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0014.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0015.png b/images/sprites/presprite/StarGreen/StarGreen_0015.png new file mode 100644 index 0000000000..14859435ff Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0015.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0016.png b/images/sprites/presprite/StarGreen/StarGreen_0016.png new file mode 100644 index 0000000000..b07fe297af Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0016.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0017.png b/images/sprites/presprite/StarGreen/StarGreen_0017.png new file mode 100644 index 0000000000..97ab4bbfa6 Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0017.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0018.png b/images/sprites/presprite/StarGreen/StarGreen_0018.png new file mode 100644 index 0000000000..95e67ab294 Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0018.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0019.png b/images/sprites/presprite/StarGreen/StarGreen_0019.png new file mode 100644 index 0000000000..d816fa9dae Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0019.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0020.png b/images/sprites/presprite/StarGreen/StarGreen_0020.png new file mode 100644 index 0000000000..25d095acba Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0020.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0021.png b/images/sprites/presprite/StarGreen/StarGreen_0021.png new file mode 100644 index 0000000000..3027a5c235 Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0021.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0022.png b/images/sprites/presprite/StarGreen/StarGreen_0022.png new file mode 100644 index 0000000000..55519c2fea Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0022.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0023.png b/images/sprites/presprite/StarGreen/StarGreen_0023.png new file mode 100644 index 0000000000..37dd2860fd Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0023.png differ diff --git a/images/sprites/presprite/StarGreen/StarGreen_0024.png b/images/sprites/presprite/StarGreen/StarGreen_0024.png new file mode 100644 index 0000000000..6cc3fd7476 Binary files /dev/null and b/images/sprites/presprite/StarGreen/StarGreen_0024.png differ diff --git a/images/sprites/presprite/Tests/Sheet.png b/images/sprites/presprite/Tests/Sheet.png new file mode 100644 index 0000000000..9d6a3f32ae Binary files /dev/null and b/images/sprites/presprite/Tests/Sheet.png differ diff --git a/images/sprites/presprite/Tests/blue.png b/images/sprites/presprite/Tests/blue.png new file mode 100644 index 0000000000..315e094faa Binary files /dev/null and b/images/sprites/presprite/Tests/blue.png differ diff --git a/images/sprites/presprite/Tests/green.png b/images/sprites/presprite/Tests/green.png new file mode 100644 index 0000000000..17bb95f532 Binary files /dev/null and b/images/sprites/presprite/Tests/green.png differ diff --git a/images/sprites/presprite/Tests/red.png b/images/sprites/presprite/Tests/red.png new file mode 100644 index 0000000000..3677002175 Binary files /dev/null and b/images/sprites/presprite/Tests/red.png differ diff --git a/images/sprites/presprite/Trees/TreeGreen.png b/images/sprites/presprite/Trees/TreeGreen.png new file mode 100644 index 0000000000..5a56ee65e9 Binary files /dev/null and b/images/sprites/presprite/Trees/TreeGreen.png differ diff --git a/images/sprites/presprite/Trees/TreeOlive.png b/images/sprites/presprite/Trees/TreeOlive.png new file mode 100644 index 0000000000..42a7ecf97d Binary files /dev/null and b/images/sprites/presprite/Trees/TreeOlive.png differ diff --git a/images/sprites/presprite/Villager1/Villager1Idle-000.png b/images/sprites/presprite/Villager1/Villager1Idle-000.png new file mode 100644 index 0000000000..921b12b4cc Binary files /dev/null and b/images/sprites/presprite/Villager1/Villager1Idle-000.png differ diff --git a/images/sprites/presprite/Villager1/Villager1Idle-001.png b/images/sprites/presprite/Villager1/Villager1Idle-001.png new file mode 100644 index 0000000000..b76aaa9059 Binary files /dev/null and b/images/sprites/presprite/Villager1/Villager1Idle-001.png differ diff --git a/images/sprites/presprite/Villager1/Villager1WalkLeft-000.png b/images/sprites/presprite/Villager1/Villager1WalkLeft-000.png new file mode 100644 index 0000000000..3d48d961c9 Binary files /dev/null and b/images/sprites/presprite/Villager1/Villager1WalkLeft-000.png differ diff --git a/images/sprites/presprite/Villager1/Villager1WalkLeft-001.png b/images/sprites/presprite/Villager1/Villager1WalkLeft-001.png new file mode 100644 index 0000000000..829fc36f42 Binary files /dev/null and b/images/sprites/presprite/Villager1/Villager1WalkLeft-001.png differ diff --git a/images/sprites/presprite/Villager1/Villager1WalkRight-000.png b/images/sprites/presprite/Villager1/Villager1WalkRight-000.png new file mode 100644 index 0000000000..09c5b8aba3 Binary files /dev/null and b/images/sprites/presprite/Villager1/Villager1WalkRight-000.png differ diff --git a/images/sprites/presprite/Villager1/Villager1WalkRight-001.png b/images/sprites/presprite/Villager1/Villager1WalkRight-001.png new file mode 100644 index 0000000000..6239fb70d3 Binary files /dev/null and b/images/sprites/presprite/Villager1/Villager1WalkRight-001.png differ diff --git a/images/sprites/presprite/Villager2/Villager2Idle-000.png b/images/sprites/presprite/Villager2/Villager2Idle-000.png new file mode 100644 index 0000000000..9d0b592eb8 Binary files /dev/null and b/images/sprites/presprite/Villager2/Villager2Idle-000.png differ diff --git a/images/sprites/presprite/Villager2/Villager2Idle-001.png b/images/sprites/presprite/Villager2/Villager2Idle-001.png new file mode 100644 index 0000000000..20accef2b8 Binary files /dev/null and b/images/sprites/presprite/Villager2/Villager2Idle-001.png differ diff --git a/images/sprites/presprite/Villager2/Villager2WalkLeft-000.png b/images/sprites/presprite/Villager2/Villager2WalkLeft-000.png new file mode 100644 index 0000000000..e5d86872bd Binary files /dev/null and b/images/sprites/presprite/Villager2/Villager2WalkLeft-000.png differ diff --git a/images/sprites/presprite/Villager2/Villager2WalkLeft-001.png b/images/sprites/presprite/Villager2/Villager2WalkLeft-001.png new file mode 100644 index 0000000000..55231ec9eb Binary files /dev/null and b/images/sprites/presprite/Villager2/Villager2WalkLeft-001.png differ diff --git a/images/sprites/presprite/Villager2/Villager2WalkRight-000.png b/images/sprites/presprite/Villager2/Villager2WalkRight-000.png new file mode 100644 index 0000000000..1a4138117d Binary files /dev/null and b/images/sprites/presprite/Villager2/Villager2WalkRight-000.png differ diff --git a/images/sprites/presprite/Villager2/Villager2WalkRight-001.png b/images/sprites/presprite/Villager2/Villager2WalkRight-001.png new file mode 100644 index 0000000000..2f7fe234ab Binary files /dev/null and b/images/sprites/presprite/Villager2/Villager2WalkRight-001.png differ diff --git a/images/sprites/presprite/Weeds/WeedBright.png b/images/sprites/presprite/Weeds/WeedBright.png new file mode 100644 index 0000000000..c09311d8e8 Binary files /dev/null and b/images/sprites/presprite/Weeds/WeedBright.png differ diff --git a/images/sprites/presprite/Weeds/WeedDark.png b/images/sprites/presprite/Weeds/WeedDark.png new file mode 100644 index 0000000000..823d6ae7a0 Binary files /dev/null and b/images/sprites/presprite/Weeds/WeedDark.png differ diff --git a/index.html b/index.html new file mode 100644 index 0000000000..6d91679af8 --- /dev/null +++ b/index.html @@ -0,0 +1,34 @@ + + + + + ScriptFoo + + + + + + + + + + + \ No newline at end of file diff --git a/lib/ace/ace.js b/lib/ace/ace.js new file mode 100644 index 0000000000..b40ab4540a --- /dev/null +++ b/lib/ace/ace.js @@ -0,0 +1,98 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +/** + * class Ace + * + * The main class required to set up an Ace instance in the browser. + * + * + **/ + +define(function(require, exports, module) { +"use strict"; + +require("./lib/fixoldbrowsers"); + +var Dom = require("./lib/dom"); +var Event = require("./lib/event"); + +var Editor = require("./editor").Editor; +var EditSession = require("./edit_session").EditSession; +var UndoManager = require("./undomanager").UndoManager; +var Renderer = require("./virtual_renderer").VirtualRenderer; +var MultiSelect = require("./multi_select").MultiSelect; + +// The following require()s are for inclusion in the built ace file +require("./worker/worker_client"); +require("./keyboard/hash_handler"); +require("./placeholder"); +require("./mode/folding/fold_mode"); +exports.config = require("./config"); + /** + * Ace.edit(el) -> Editor + * - el (String | DOMElement): Either the id of an element, or the element itself + * + * This method embeds the Ace editor into the DOM, at the element provided by `el`. + * + **/ +exports.edit = function(el) { + if (typeof(el) == "string") { + var _id = el; + if (!(el = document.getElementById(el))) + throw "ace.edit can't find div #" + _id; + } + + if (el.env && el.env.editor instanceof Editor) + return el.env.editor; + + var doc = new EditSession(Dom.getInnerText(el)); + doc.setUndoManager(new UndoManager()); + el.innerHTML = ''; + + var editor = new Editor(new Renderer(el, require("./theme/textmate"))); + new MultiSelect(editor); + editor.setSession(doc); + + var env = {}; + env.document = doc; + env.editor = editor; + editor.resize(); + Event.addListener(window, "resize", function() { + editor.resize(); + }); + el.env = env; + // Store env on editor such that it can be accessed later on from + // the returned object. + editor.env = env; + return editor; +}; + +}); diff --git a/lib/ace/anchor.js b/lib/ace/anchor.js new file mode 100644 index 0000000000..b10755bb85 --- /dev/null +++ b/lib/ace/anchor.js @@ -0,0 +1,252 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("./lib/oop"); +var EventEmitter = require("./lib/event_emitter").EventEmitter; + +/** + * class Anchor + * + * Defines the floating pointer in the document. Whenever text is inserted or deleted before the cursor, the position of the cursor is updated + * + **/ + +/** + * new Anchor(doc, row, column) + * - doc (Document): The document to associate with the anchor + * - row (Number): The starting row position + * - column (Number): The starting column position + * + * Creates a new `Anchor` and associates it with a document. + * + **/ + +var Anchor = exports.Anchor = function(doc, row, column) { + this.document = doc; + + if (typeof column == "undefined") + this.setPosition(row.row, row.column); + else + this.setPosition(row, column); + + this.$onChange = this.onChange.bind(this); + doc.on("change", this.$onChange); +}; + +(function() { + + oop.implement(this, EventEmitter); + + /** + * Anchor.getPosition() -> Object + * + * Returns an object identifying the `row` and `column` position of the current anchor. + * + **/ + + this.getPosition = function() { + return this.$clipPositionToDocument(this.row, this.column); + }; + + /** + * Anchor.getDocument() -> Document + * + * Returns the current document. + * + **/ + + this.getDocument = function() { + return this.document; + }; + + /** + * Anchor@change(e) + * - e (Object): An object containing information about the anchor position. It has two properties: + * `old`: An object describing the old Anchor position + * `value`: An object describing the new Anchor position + Both of these objects have a `row` and `column` property corresponding to the position. + * + * Fires whenever the anchor position changes. + * + * Events that can trigger this function include [[Anchor.setPosition `setPosition()`]]. + * + **/ + + this.onChange = function(e) { + var delta = e.data; + var range = delta.range; + + if (range.start.row == range.end.row && range.start.row != this.row) + return; + + if (range.start.row > this.row) + return; + + if (range.start.row == this.row && range.start.column > this.column) + return; + + var row = this.row; + var column = this.column; + + if (delta.action === "insertText") { + if (range.start.row === row && range.start.column <= column) { + if (range.start.row === range.end.row) { + column += range.end.column - range.start.column; + } + else { + column -= range.start.column; + row += range.end.row - range.start.row; + } + } + else if (range.start.row !== range.end.row && range.start.row < row) { + row += range.end.row - range.start.row; + } + } else if (delta.action === "insertLines") { + if (range.start.row <= row) { + row += range.end.row - range.start.row; + } + } + else if (delta.action == "removeText") { + if (range.start.row == row && range.start.column < column) { + if (range.end.column >= column) + column = range.start.column; + else + column = Math.max(0, column - (range.end.column - range.start.column)); + + } else if (range.start.row !== range.end.row && range.start.row < row) { + if (range.end.row == row) { + column = Math.max(0, column - range.end.column) + range.start.column; + } + row -= (range.end.row - range.start.row); + } + else if (range.end.row == row) { + row -= range.end.row - range.start.row; + column = Math.max(0, column - range.end.column) + range.start.column; + } + } else if (delta.action == "removeLines") { + if (range.start.row <= row) { + if (range.end.row <= row) + row -= range.end.row - range.start.row; + else { + row = range.start.row; + column = 0; + } + } + } + + this.setPosition(row, column, true); + }; + + /** + * Anchor.setPosition(row, column, noClip) + * - row (Number): The row index to move the anchor to + * - column (Number): The column index to move the anchor to + * - noClip (Boolean): Identifies if you want the position to be clipped + * + * Sets the anchor position to the specified row and column. If `noClip` is `true`, the position is not clipped. + * + **/ + + this.setPosition = function(row, column, noClip) { + var pos; + if (noClip) { + pos = { + row: row, + column: column + }; + } + else { + pos = this.$clipPositionToDocument(row, column); + } + + if (this.row == pos.row && this.column == pos.column) + return; + + var old = { + row: this.row, + column: this.column + }; + + this.row = pos.row; + this.column = pos.column; + this._emit("change", { + old: old, + value: pos + }); + }; + + /** + * Anchor.detach() + * + * When called, the `'change'` event listener is removed. + * + **/ + + this.detach = function() { + this.document.removeEventListener("change", this.$onChange); + }; + + /** internal, hide + * Anchor.clipPositionToDocument(row, column) + * - row (Number): The row index to clip the anchor to + * - column (Number): The column index to clip the anchor to + * + * Clips the anchor position to the specified row and column. + * + **/ + + this.$clipPositionToDocument = function(row, column) { + var pos = {}; + + if (row >= this.document.getLength()) { + pos.row = Math.max(0, this.document.getLength() - 1); + pos.column = this.document.getLine(pos.row).length; + } + else if (row < 0) { + pos.row = 0; + pos.column = 0; + } + else { + pos.row = row; + pos.column = Math.min(this.document.getLine(pos.row).length, Math.max(0, column)); + } + + if (column < 0) + pos.column = 0; + + return pos; + }; + +}).call(Anchor.prototype); + +}); diff --git a/lib/ace/anchor_test.js b/lib/ace/anchor_test.js new file mode 100644 index 0000000000..b9c5cd6636 --- /dev/null +++ b/lib/ace/anchor_test.js @@ -0,0 +1,177 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); +} + +define(function(require, exports, module) { +"use strict"; + +var Document = require("./document").Document; +var Anchor = require("./anchor").Anchor; +var Range = require("./range").Range; +var assert = require("./test/assertions"); + +module.exports = { + + "test create anchor" : function() { + var doc = new Document("juhu"); + var anchor = new Anchor(doc, 0, 0); + + assert.position(anchor.getPosition(), 0, 0); + assert.equal(anchor.getDocument(), doc); + }, + + "test insert text in same row before cursor should move anchor column": function() { + var doc = new Document("juhu\nkinners"); + var anchor = new Anchor(doc, 1, 4); + + doc.insert({row: 1, column: 1}, "123"); + assert.position(anchor.getPosition(), 1, 7); + }, + + "test insert lines before cursor should move anchor row": function() { + var doc = new Document("juhu\nkinners"); + var anchor = new Anchor(doc, 1, 4); + + doc.insertLines(1, ["123", "456"]); + assert.position(anchor.getPosition(), 3, 4); + }, + + "test insert new line before cursor should move anchor column": function() { + var doc = new Document("juhu\nkinners"); + var anchor = new Anchor(doc, 1, 4); + + doc.insertNewLine({row: 0, column: 0}); + assert.position(anchor.getPosition(), 2, 4); + }, + + "test insert new line in anchor line before anchor should move anchor column and row": function() { + var doc = new Document("juhu\nkinners"); + var anchor = new Anchor(doc, 1, 4); + + doc.insertNewLine({row: 1, column: 2}); + assert.position(anchor.getPosition(), 2, 2); + }, + + "test delete text in anchor line before anchor should move anchor column": function() { + var doc = new Document("juhu\nkinners"); + var anchor = new Anchor(doc, 1, 4); + + doc.remove(new Range(1, 1, 1, 3)); + assert.position(anchor.getPosition(), 1, 2); + }, + + "test remove range which contains the anchor should move the anchor to the start of the range": function() { + var doc = new Document("juhu\nkinners"); + var anchor = new Anchor(doc, 0, 3); + + doc.remove(new Range(0, 1, 1, 3)); + assert.position(anchor.getPosition(), 0, 1); + }, + + "test delete character before the anchor should have no effect": function() { + var doc = new Document("juhu\nkinners"); + var anchor = new Anchor(doc, 1, 4); + + doc.remove(new Range(1, 4, 1, 5)); + assert.position(anchor.getPosition(), 1, 4); + }, + + "test delete lines in anchor line before anchor should move anchor row": function() { + var doc = new Document("juhu\n1\n2\nkinners"); + var anchor = new Anchor(doc, 3, 4); + + doc.removeLines(1, 2); + assert.position(anchor.getPosition(), 1, 4); + }, + + "test remove new line before the cursor": function() { + var doc = new Document("juhu\nkinners"); + var anchor = new Anchor(doc, 1, 4); + + doc.removeNewLine(0); + assert.position(anchor.getPosition(), 0, 8); + }, + + "test delete range which contains the anchor should move anchor to the end of the range": function() { + var doc = new Document("juhu\nkinners"); + var anchor = new Anchor(doc, 1, 4); + + doc.remove(new Range(0, 2, 1, 2)); + assert.position(anchor.getPosition(), 0, 4); + }, + + "test delete line which contains the anchor should move anchor to the end of the range": function() { + var doc = new Document("juhu\nkinners\n123"); + var anchor = new Anchor(doc, 1, 5); + + doc.removeLines(1, 1); + assert.position(anchor.getPosition(), 1, 0); + }, + + "test remove after the anchor should have no effect": function() { + var doc = new Document("juhu\nkinners\n123"); + var anchor = new Anchor(doc, 1, 2); + + doc.remove(new Range(1, 4, 2, 2)); + assert.position(anchor.getPosition(), 1, 2); + }, + + "test anchor changes triggered by document changes should emit change event": function(next) { + var doc = new Document("juhu\nkinners\n123"); + var anchor = new Anchor(doc, 1, 5); + + anchor.on("change", function(e) { + assert.position(anchor.getPosition(), 0, 0); + next(); + }); + + doc.remove(new Range(0, 0, 2, 1)); + }, + + "test only fire change event if position changes": function() { + var doc = new Document("juhu\nkinners\n123"); + var anchor = new Anchor(doc, 1, 5); + + anchor.on("change", function(e) { + assert.fail(); + }); + + doc.remove(new Range(2, 0, 2, 1)); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec() +} diff --git a/lib/ace/background_tokenizer.js b/lib/ace/background_tokenizer.js new file mode 100644 index 0000000000..08a46d5d8e --- /dev/null +++ b/lib/ace/background_tokenizer.js @@ -0,0 +1,260 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("./lib/oop"); +var EventEmitter = require("./lib/event_emitter").EventEmitter; + +// tokenizing lines longer than this makes editor very slow +var MAX_LINE_LENGTH = 5000; + +/** + * class BackgroundTokenizer + * + * Tokenizes the current [[Document `Document`]] in the background, and caches the tokenized rows for future use. If a certain row is changed, everything below that row is re-tokenized. + * + **/ + +/** + * new BackgroundTokenizer(tokenizer, editor) + * - tokenizer (Tokenizer): The tokenizer to use + * - editor (Editor): The editor to associate with + * + * Creates a new `BackgroundTokenizer` object. + * + * + **/ + +var BackgroundTokenizer = function(tokenizer, editor) { + this.running = false; + this.lines = []; + this.states = []; + this.currentLine = 0; + this.tokenizer = tokenizer; + + var self = this; + + this.$worker = function() { + if (!self.running) { return; } + + var workerStart = new Date(); + var startLine = self.currentLine; + var doc = self.doc; + + var processedLines = 0; + + var len = doc.getLength(); + while (self.currentLine < len) { + self.$tokenizeRow(self.currentLine); + while (self.lines[self.currentLine]) + self.currentLine++; + + // only check every 5 lines + processedLines ++; + if ((processedLines % 5 == 0) && (new Date() - workerStart) > 20) { + self.fireUpdateEvent(startLine, self.currentLine-1); + self.running = setTimeout(self.$worker, 20); + return; + } + } + + self.running = false; + + self.fireUpdateEvent(startLine, len - 1); + }; +}; + +(function(){ + + oop.implement(this, EventEmitter); + + /** + * BackgroundTokenizer.setTokenizer(tokenizer) + * - tokenizer (Tokenizer): The new tokenizer to use + * + * Sets a new tokenizer for this object. + * + **/ + this.setTokenizer = function(tokenizer) { + this.tokenizer = tokenizer; + this.lines = []; + this.states = []; + + this.start(0); + }; + + /** + * BackgroundTokenizer.setDocument(doc) + * - doc (Document): The new document to associate with + * + * Sets a new document to associate with this object. + * + **/ + this.setDocument = function(doc) { + this.doc = doc; + this.lines = []; + this.states = []; + + this.stop(); + }; + + /** + * BackgroundTokenizer.fireUpdateEvent(firstRow, lastRow) + * - firstRow (Number): The starting row region + * - lastRow (Number): The final row region + * + * Emits the `'update'` event. `firstRow` and `lastRow` are used to define the boundaries of the region to be updated. + * + **/ + /** + * BackgroundTokenizer@update(e) + * - e (Object): An object containing two properties, `first` and `last`, which indicate the rows of the region being updated. + * + * Fires whenever the background tokeniziers between a range of rows are going to be updated. + * + **/ + this.fireUpdateEvent = function(firstRow, lastRow) { + var data = { + first: firstRow, + last: lastRow + }; + this._emit("update", {data: data}); + }; + + /** + * BackgroundTokenizer.start(startRow) + * - startRow (Number): The row to start at + * + * Starts tokenizing at the row indicated. + * + **/ + this.start = function(startRow) { + this.currentLine = Math.min(startRow || 0, this.currentLine, this.doc.getLength()); + + // remove all cached items below this line + this.lines.splice(this.currentLine, this.lines.length); + this.states.splice(this.currentLine, this.states.length); + + this.stop(); + // pretty long delay to prevent the tokenizer from interfering with the user + this.running = setTimeout(this.$worker, 700); + }; + + this.$updateOnChange = function(delta) { + var range = delta.range; + var startRow = range.start.row; + var len = range.end.row - startRow; + + if (len === 0) { + this.lines[startRow] = null; + } else if (delta.action == "removeText" || delta.action == "removeLines") { + this.lines.splice(startRow, len + 1, null); + this.states.splice(startRow, len + 1, null); + } else { + var args = Array(len + 1); + args.unshift(startRow, 1); + this.lines.splice.apply(this.lines, args); + this.states.splice.apply(this.states, args); + } + + this.currentLine = Math.min(startRow, this.currentLine, this.doc.getLength()); + + this.stop(); + // pretty long delay to prevent the tokenizer from interfering with the user + this.running = setTimeout(this.$worker, 700); + }; + + /** + * BackgroundTokenizer.stop() + * + * Stops tokenizing. + * + **/ + this.stop = function() { + if (this.running) + clearTimeout(this.running); + this.running = false; + }; + + /** + * BackgroundTokenizer.getTokens(row) -> [Object] + * - row (Number): The row to get tokens at + * + * Gives list of tokens of the row. (tokens are cached) + * + **/ + this.getTokens = function(row) { + return this.lines[row] || this.$tokenizeRow(row); + }; + + /** + * BackgroundTokenizer.getState(row) -> String + * - row (Number): The row to get state at + * + * [Returns the state of tokenization at the end of a row.]{: #BackgroundTokenizer.getState} + **/ + this.getState = function(row) { + if (this.currentLine == row) + this.$tokenizeRow(row); + return this.states[row] || "start"; + }; + + this.$tokenizeRow = function(row) { + var line = this.doc.getLine(row); + var state = this.states[row - 1]; + + if (line.length > MAX_LINE_LENGTH) { + var overflow = {value: line.substr(MAX_LINE_LENGTH), type: "text"}; + line = line.slice(0, MAX_LINE_LENGTH); + } + var data = this.tokenizer.getLineTokens(line, state); + if (overflow) { + data.tokens.push(overflow); + data.state = "start"; + } + + if (this.states[row] !== data.state) { + this.states[row] = data.state; + this.lines[row + 1] = null; + if (this.currentLine > row + 1) + this.currentLine = row + 1; + } else if (this.currentLine == row) { + this.currentLine = row + 1; + } + + return this.lines[row] = data.tokens; + }; + +}).call(BackgroundTokenizer.prototype); + +exports.BackgroundTokenizer = BackgroundTokenizer; +}); diff --git a/lib/ace/background_tokenizer_test.js b/lib/ace/background_tokenizer_test.js new file mode 100644 index 0000000000..c62e33f15c --- /dev/null +++ b/lib/ace/background_tokenizer_test.js @@ -0,0 +1,85 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); +} + +define(function(require, exports, module) { +"use strict"; + +var EditSession = require("./edit_session").EditSession; +var JavaScriptMode = require("./mode/javascript").Mode; +var Range = require("./range").Range; +var assert = require("./test/assertions"); + +function forceTokenize(session){ + for (var i = 0, l = session.getLength(); i < l; i++) + session.getTokens(i) +} + +function testStates(session, states) { + for (var i = 0, l = session.getLength(); i < l; i++) + assert.equal(session.bgTokenizer.states[i], states[i]) + assert.ok(l == states.length) +} + +module.exports = { + + "test background tokenizer update on session change" : function() { + var doc = new EditSession([ + "/*", + "*/", + "var juhu" + ]); + doc.setMode("./mode/javascript") + + forceTokenize(doc) + testStates(doc, ["comment", "start", "start"]) + + doc.remove(new Range(0,2,1,2)) + testStates(doc, [null, "start"]) + + forceTokenize(doc) + testStates(doc, ["comment", "comment"]) + + doc.insert({row:0, column:2}, "\n*/") + testStates(doc, [undefined, undefined, "comment"]) + + forceTokenize(doc) + testStates(doc, ["comment", "start", "start"]) + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec() +} diff --git a/lib/ace/commands/command_manager.js b/lib/ace/commands/command_manager.js new file mode 100644 index 0000000000..2686364352 --- /dev/null +++ b/lib/ace/commands/command_manager.js @@ -0,0 +1,123 @@ +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var HashHandler = require("../keyboard/hash_handler").HashHandler; +var EventEmitter = require("../lib/event_emitter").EventEmitter; + +/** + * class CommandManager + * + * + * + * + **/ + +/** + * new CommandManager(platform, commands) + * - platform (String): Identifier for the platform; must be either `'mac'` or `'win'` + * - commands (Array): A list of commands + * + * TODO + * + * + **/ + +var CommandManager = function(platform, commands) { + this.platform = platform; + this.commands = this.byName = {}; + this.commmandKeyBinding = {}; + + this.addCommands(commands); + + this.setDefaultHandler("exec", function(e) { + return e.command.exec(e.editor, e.args || {}); + }); +}; + +oop.inherits(CommandManager, HashHandler); + +(function() { + + oop.implement(this, EventEmitter); + + this.exec = function(command, editor, args) { + if (typeof command === 'string') + command = this.commands[command]; + + if (!command) + return false; + + if (editor && editor.$readOnly && !command.readOnly) + return false; + + var retvalue = this._emit("exec", { + editor: editor, + command: command, + args: args + }); + + return retvalue === false ? false : true; + }; + + this.toggleRecording = function(editor) { + if (this.$inReplay) + return; + + editor && editor._emit("changeStatus"); + if (this.recording) { + this.macro.pop(); + this.removeEventListener("exec", this.$addCommandToMacro); + + if (!this.macro.length) + this.macro = this.oldMacro; + + return this.recording = false; + } + if (!this.$addCommandToMacro) { + this.$addCommandToMacro = function(e) { + this.macro.push([e.command, e.args]); + }.bind(this); + } + + this.oldMacro = this.macro; + this.macro = []; + this.on("exec", this.$addCommandToMacro); + return this.recording = true; + }; + + this.replay = function(editor) { + if (this.$inReplay || !this.macro) + return; + + if (this.recording) + return this.toggleRecording(editor); + + try { + this.$inReplay = true; + this.macro.forEach(function(x) { + if (typeof x == "string") + this.exec(x, editor); + else + this.exec(x[0], editor, x[1]); + }, this); + } finally { + this.$inReplay = false; + } + }; + + this.trimMacro = function(m) { + return m.map(function(x){ + if (typeof x[0] != "string") + x[0] = x[0].name; + if (!x[1]) + x = x[0]; + return x; + }); + }; + +}).call(CommandManager.prototype); + +exports.CommandManager = CommandManager; + +}); diff --git a/lib/ace/commands/command_manager_test.js b/lib/ace/commands/command_manager_test.js new file mode 100644 index 0000000000..76d973bbb2 --- /dev/null +++ b/lib/ace/commands/command_manager_test.js @@ -0,0 +1,199 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); +} + +define(function(require, exports, module) { +"use strict"; + +var CommandManager = require("./command_manager").CommandManager; +var keys = require("../lib/keys"); +var assert = require("../test/assertions"); + +module.exports = { + + setUp: function() { + this.command = { + name: "gotoline", + bindKey: { + mac: "Command-L", + win: "Ctrl-L" + }, + called: false, + exec: function(editor) { this.called = true; } + }; + + this.cm = new CommandManager("mac", [this.command]); + }, + + "test: register command": function() { + this.cm.exec("gotoline"); + assert.ok(this.command.called); + }, + + "test: mac hotkeys": function() { + var command = this.cm.findKeyCommand(keys.KEY_MODS.command, "l"); + assert.equal(command, this.command); + + var command = this.cm.findKeyCommand(keys.KEY_MODS.ctrl, "l"); + assert.equal(command, undefined); + }, + + "test: win hotkeys": function() { + var cm = new CommandManager("win", [this.command]); + + var command = cm.findKeyCommand(keys.KEY_MODS.command, "l"); + assert.equal(command, undefined); + + var command = cm.findKeyCommand(keys.KEY_MODS.ctrl, "l"); + assert.equal(command, this.command); + }, + + "test: remove command by object": function() { + this.cm.removeCommand(this.command); + + this.cm.exec("gotoline"); + assert.ok(!this.command.called); + + var command = this.cm.findKeyCommand(keys.KEY_MODS.command, "l"); + assert.equal(command, null); + }, + + "test: remove command by name": function() { + this.cm.removeCommand("gotoline"); + + this.cm.exec("gotoline"); + assert.ok(!this.command.called); + + var command = this.cm.findKeyCommand(keys.KEY_MODS.command, "l"); + assert.equal(command, null); + }, + + "test: adding a new command with the same name as an existing one should remove the old one first": function() { + var command = { + name: "gotoline", + bindKey: { + mac: "Command-L", + win: "Ctrl-L" + }, + called: false, + exec: function(editor) { this.called = true; } + }; + this.cm.addCommand(command); + + this.cm.exec("gotoline"); + assert.ok(command.called); + assert.ok(!this.command.called); + + assert.equal(this.cm.findKeyCommand(keys.KEY_MODS.command, "l"), command); + }, + + "test: adding commands and recording a macro": function() { + var called = ""; + this.cm.addCommands({ + togglerecording: function(editor) { + editor.cm.toggleRecording(editor); + }, + replay: function(editor) { + editor.cm.replay(); + }, + cm1: function(editor, arg) { + called += "1" + (arg || ""); + }, + cm2: function(editor) { + called += "2"; + } + }); + + + var statusUpdateEmitted = false; + this._emit = function() {statusUpdateEmitted = true}; + + this.cm.exec("togglerecording", this); + assert.ok(this.cm.recording); + assert.ok(statusUpdateEmitted); + + this.cm.exec("cm1", this, "-"); + this.cm.exec("cm2"); + this.cm.exec("replay", this); + assert.ok(!this.cm.recording); + assert.equal(called, "1-2"); + + called = ""; + this.cm.exec("replay", this); + assert.equal(called, "1-2"); + }, + + "test: bindkeys": function() { + this.cm.bindKeys({ + "Ctrl-L|Command-C": "cm1", + "Ctrl-R": "cm2" + }); + + var command = this.cm.findKeyCommand(keys.KEY_MODS.command, "c"); + assert.equal(command, "cm1"); + + var command = this.cm.findKeyCommand(keys.KEY_MODS.ctrl, "r"); + assert.equal(command, "cm2"); + + this.cm.bindKeys({ + "Ctrl-R": null + }); + + var command = this.cm.findKeyCommand(keys.KEY_MODS.ctrl, "r"); + assert.equal(command, null); + }, + + "test: binding keys without modifiers": function() { + this.cm.bindKeys({ + "R": "cm1", + "Shift-r": "cm2", + "Return": "cm4", + "Enter": "cm3" + }); + + var command = this.cm.findKeyCommand(-1, "r"); + assert.equal(command, "cm1"); + + var command = this.cm.findKeyCommand(-1, "R"); + assert.equal(command, "cm2"); + + var command = this.cm.findKeyCommand(0, "return"); + assert.equal(command, "cm3"); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/lib/ace/commands/default_commands.js b/lib/ace/commands/default_commands.js new file mode 100644 index 0000000000..8c33fc42d9 --- /dev/null +++ b/lib/ace/commands/default_commands.js @@ -0,0 +1,467 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var lang = require("../lib/lang"); + +function bindKey(win, mac) { + return { + win: win, + mac: mac + }; +} + +exports.commands = [{ + name: "selectall", + bindKey: bindKey("Ctrl-A", "Command-A"), + exec: function(editor) { editor.selectAll(); }, + readOnly: true +}, { + name: "centerselection", + bindKey: bindKey(null, "Ctrl-L"), + exec: function(editor) { editor.centerSelection(); }, + readOnly: true +}, { + name: "gotoline", + bindKey: bindKey("Ctrl-L", "Command-L"), + exec: function(editor) { + var line = parseInt(prompt("Enter line number:"), 10); + if (!isNaN(line)) { + editor.gotoLine(line); + } + }, + readOnly: true +}, { + name: "fold", + bindKey: bindKey("Alt-L|Ctrl-F1", "Command-Alt-L|Command-F1"), + exec: function(editor) { editor.session.toggleFold(false); }, + readOnly: true +}, { + name: "unfold", + bindKey: bindKey("Alt-Shift-L|Ctrl-Shift-F1", "Command-Alt-Shift-L|Command-Shift-F1"), + exec: function(editor) { editor.session.toggleFold(true); }, + readOnly: true +}, { + name: "foldall", + bindKey: bindKey("Alt-0", "Command-Option-0"), + exec: function(editor) { editor.session.foldAll(); }, + readOnly: true +}, { + name: "unfoldall", + bindKey: bindKey("Alt-Shift-0", "Command-Option-Shift-0"), + exec: function(editor) { editor.session.unfold(); }, + readOnly: true +}, { + name: "findnext", + bindKey: bindKey("Ctrl-K", "Command-G"), + exec: function(editor) { editor.findNext(); }, + readOnly: true +}, { + name: "findprevious", + bindKey: bindKey("Ctrl-Shift-K", "Command-Shift-G"), + exec: function(editor) { editor.findPrevious(); }, + readOnly: true +}, { + name: "find", + bindKey: bindKey("Ctrl-F", "Command-F"), + exec: function(editor) { + var needle = prompt("Find:", editor.getCopyText()); + editor.find(needle); + }, + readOnly: true +}, { + name: "overwrite", + bindKey: "Insert", + exec: function(editor) { editor.toggleOverwrite(); }, + readOnly: true +}, { + name: "selecttostart", + bindKey: bindKey("Ctrl-Shift-Home", "Command-Shift-Up"), + exec: function(editor) { editor.getSelection().selectFileStart(); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "gotostart", + bindKey: bindKey("Ctrl-Home", "Command-Home|Command-Up"), + exec: function(editor) { editor.navigateFileStart(); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "selectup", + bindKey: bindKey("Shift-Up", "Shift-Up"), + exec: function(editor) { editor.getSelection().selectUp(); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "golineup", + bindKey: bindKey("Up", "Up|Ctrl-P"), + exec: function(editor, args) { editor.navigateUp(args.times); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "selecttoend", + bindKey: bindKey("Ctrl-Shift-End", "Command-Shift-Down"), + exec: function(editor) { editor.getSelection().selectFileEnd(); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "gotoend", + bindKey: bindKey("Ctrl-End", "Command-End|Command-Down"), + exec: function(editor) { editor.navigateFileEnd(); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "selectdown", + bindKey: bindKey("Shift-Down", "Shift-Down"), + exec: function(editor) { editor.getSelection().selectDown(); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "golinedown", + bindKey: bindKey("Down", "Down|Ctrl-N"), + exec: function(editor, args) { editor.navigateDown(args.times); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "selectwordleft", + bindKey: bindKey("Ctrl-Shift-Left", "Option-Shift-Left"), + exec: function(editor) { editor.getSelection().selectWordLeft(); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "gotowordleft", + bindKey: bindKey("Ctrl-Left", "Option-Left"), + exec: function(editor) { editor.navigateWordLeft(); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "selecttolinestart", + bindKey: bindKey("Alt-Shift-Left", "Command-Shift-Left"), + exec: function(editor) { editor.getSelection().selectLineStart(); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "gotolinestart", + bindKey: bindKey("Alt-Left|Home", "Command-Left|Home|Ctrl-A"), + exec: function(editor) { editor.navigateLineStart(); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "selectleft", + bindKey: bindKey("Shift-Left", "Shift-Left"), + exec: function(editor) { editor.getSelection().selectLeft(); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "gotoleft", + bindKey: bindKey("Left", "Left|Ctrl-B"), + exec: function(editor, args) { editor.navigateLeft(args.times); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "selectwordright", + bindKey: bindKey("Ctrl-Shift-Right", "Option-Shift-Right"), + exec: function(editor) { editor.getSelection().selectWordRight(); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "gotowordright", + bindKey: bindKey("Ctrl-Right", "Option-Right"), + exec: function(editor) { editor.navigateWordRight(); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "selecttolineend", + bindKey: bindKey("Alt-Shift-Right", "Command-Shift-Right"), + exec: function(editor) { editor.getSelection().selectLineEnd(); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "gotolineend", + bindKey: bindKey("Alt-Right|End", "Command-Right|End|Ctrl-E"), + exec: function(editor) { editor.navigateLineEnd(); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "selectright", + bindKey: bindKey("Shift-Right", "Shift-Right"), + exec: function(editor) { editor.getSelection().selectRight(); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "gotoright", + bindKey: bindKey("Right", "Right|Ctrl-F"), + exec: function(editor, args) { editor.navigateRight(args.times); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "selectpagedown", + bindKey: "Shift-PageDown", + exec: function(editor) { editor.selectPageDown(); }, + readOnly: true +}, { + name: "pagedown", + bindKey: bindKey(null, "Option-PageDown"), + exec: function(editor) { editor.scrollPageDown(); }, + readOnly: true +}, { + name: "gotopagedown", + bindKey: bindKey("PageDown", "PageDown|Ctrl-V"), + exec: function(editor) { editor.gotoPageDown(); }, + readOnly: true +}, { + name: "selectpageup", + bindKey: "Shift-PageUp", + exec: function(editor) { editor.selectPageUp(); }, + readOnly: true +}, { + name: "pageup", + bindKey: bindKey(null, "Option-PageUp"), + exec: function(editor) { editor.scrollPageUp(); }, + readOnly: true +}, { + name: "gotopageup", + bindKey: "PageUp", + exec: function(editor) { editor.gotoPageUp(); }, + readOnly: true +}, { + name: "scrollup", + bindKey: bindKey("Ctrl-Up", null), + exec: function(e) { e.renderer.scrollBy(0, -2 * e.renderer.layerConfig.lineHeight); }, + readOnly: true +}, { + name: "scrolldown", + bindKey: bindKey("Ctrl-Down", null), + exec: function(e) { e.renderer.scrollBy(0, 2 * e.renderer.layerConfig.lineHeight); }, + readOnly: true +}, { + name: "selectlinestart", + bindKey: "Shift-Home", + exec: function(editor) { editor.getSelection().selectLineStart(); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "selectlineend", + bindKey: "Shift-End", + exec: function(editor) { editor.getSelection().selectLineEnd(); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "togglerecording", + bindKey: bindKey("Ctrl-Alt-E", "Command-Option-E"), + exec: function(editor) { editor.commands.toggleRecording(editor); }, + readOnly: true +}, { + name: "replaymacro", + bindKey: bindKey("Ctrl-Shift-E", "Command-Shift-E"), + exec: function(editor) { editor.commands.replay(editor); }, + readOnly: true +}, { + name: "jumptomatching", + bindKey: bindKey("Ctrl-P", "Ctrl-Shift-P"), + exec: function(editor) { editor.jumpToMatching(); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "selecttomatching", + bindKey: bindKey("Ctrl-Shift-P", null), + exec: function(editor) { editor.jumpToMatching(true); }, + readOnly: true +}, + +// commands disabled in readOnly mode +{ + name: "cut", + exec: function(editor) { + var range = editor.getSelectionRange(); + editor._emit("cut", range); + + if (!editor.selection.isEmpty()) { + editor.session.remove(range); + editor.clearSelection(); + } + }, + multiSelectAction: "forEach" +}, { + name: "removeline", + bindKey: bindKey("Ctrl-D", "Command-D"), + exec: function(editor) { editor.removeLines(); }, + multiSelectAction: "forEach" +}, { + name: "duplicateSelection", + bindKey: bindKey("Ctrl-Shift-D", "Command-Shift-D"), + exec: function(editor) { editor.duplicateSelection(); }, + multiSelectAction: "forEach" +}, { + name: "sortlines", + bindKey: bindKey("Ctrl-Alt-S", "Command-Alt-S"), + exec: function(editor) { editor.sortLines(); }, + multiSelectAction: "forEach" +}, { + name: "togglecomment", + bindKey: bindKey("Ctrl-/", "Command-/"), + exec: function(editor) { editor.toggleCommentLines(); }, + multiSelectAction: "forEach" +}, { + name: "modifyNumberUp", + bindKey: bindKey("Ctrl-Shift-Up", "Alt-Shift-Up"), + exec: function(editor) { editor.modifyNumber(1); }, + multiSelectAction: "forEach" +}, { + name: "modifyNumberDown", + bindKey: bindKey("Ctrl-Shift-Down", "Alt-Shift-Down"), + exec: function(editor) { editor.modifyNumber(-1); }, + multiSelectAction: "forEach" +}, { + name: "replace", + bindKey: bindKey("Ctrl-R", "Command-Option-F"), + exec: function(editor) { + var needle = prompt("Find:", editor.getCopyText()); + if (!needle) + return; + var replacement = prompt("Replacement:"); + if (!replacement) + return; + editor.replace(replacement, {needle: needle}); + } +}, { + name: "replaceall", + bindKey: bindKey("Ctrl-Shift-R", "Command-Shift-Option-F"), + exec: function(editor) { + var needle = prompt("Find:"); + if (!needle) + return; + var replacement = prompt("Replacement:"); + if (!replacement) + return; + editor.replaceAll(replacement, {needle: needle}); + } +}, { + name: "undo", + bindKey: bindKey("Ctrl-Z", "Command-Z"), + exec: function(editor) { editor.undo(); } +}, { + name: "redo", + bindKey: bindKey("Ctrl-Shift-Z|Ctrl-Y", "Command-Shift-Z|Command-Y"), + exec: function(editor) { editor.redo(); } +}, { + name: "copylinesup", + bindKey: bindKey("Alt-Shift-Up", "Command-Option-Up"), + exec: function(editor) { editor.copyLinesUp(); } +}, { + name: "movelinesup", + bindKey: bindKey("Alt-Up", "Option-Up"), + exec: function(editor) { editor.moveLinesUp(); } +}, { + name: "copylinesdown", + bindKey: bindKey("Alt-Shift-Down", "Command-Option-Down"), + exec: function(editor) { editor.copyLinesDown(); } +}, { + name: "movelinesdown", + bindKey: bindKey("Alt-Down", "Option-Down"), + exec: function(editor) { editor.moveLinesDown(); } +}, { + name: "del", + bindKey: bindKey("Delete", "Delete|Ctrl-D"), + exec: function(editor) { editor.remove("right"); }, + multiSelectAction: "forEach" +}, { + name: "backspace", + bindKey: bindKey( + "Command-Backspace|Option-Backspace|Shift-Backspace|Backspace", + "Ctrl-Backspace|Command-Backspace|Shift-Backspace|Backspace|Ctrl-H" + ), + exec: function(editor) { editor.remove("left"); }, + multiSelectAction: "forEach" +}, { + name: "removetolinestart", + bindKey: bindKey("Alt-Backspace", "Command-Backspace"), + exec: function(editor) { editor.removeToLineStart(); }, + multiSelectAction: "forEach" +}, { + name: "removetolineend", + bindKey: bindKey("Alt-Delete", "Ctrl-K"), + exec: function(editor) { editor.removeToLineEnd(); }, + multiSelectAction: "forEach" +}, { + name: "removewordleft", + bindKey: bindKey("Ctrl-Backspace", "Alt-Backspace|Ctrl-Alt-Backspace"), + exec: function(editor) { editor.removeWordLeft(); }, + multiSelectAction: "forEach" +}, { + name: "removewordright", + bindKey: bindKey("Ctrl-Delete", "Alt-Delete"), + exec: function(editor) { editor.removeWordRight(); }, + multiSelectAction: "forEach" +}, { + name: "outdent", + bindKey: bindKey("Shift-Tab", "Shift-Tab"), + exec: function(editor) { editor.blockOutdent(); }, + multiSelectAction: "forEach" +}, { + name: "indent", + bindKey: bindKey("Tab", "Tab"), + exec: function(editor) { editor.indent(); }, + multiSelectAction: "forEach" +}, { + name: "insertstring", + exec: function(editor, str) { editor.insert(str); }, + multiSelectAction: "forEach" +}, { + name: "inserttext", + exec: function(editor, args) { + editor.insert(lang.stringRepeat(args.text || "", args.times || 1)); + }, + multiSelectAction: "forEach" +}, { + name: "splitline", + bindKey: bindKey(null, "Ctrl-O"), + exec: function(editor) { editor.splitLine(); }, + multiSelectAction: "forEach" +}, { + name: "transposeletters", + bindKey: bindKey("Ctrl-T", "Ctrl-T"), + exec: function(editor) { editor.transposeLetters(); }, + multiSelectAction: function(editor) {editor.transposeSelections(1); } +}, { + name: "touppercase", + bindKey: bindKey("Ctrl-U", "Ctrl-U"), + exec: function(editor) { editor.toUpperCase(); }, + multiSelectAction: "forEach" +}, { + name: "tolowercase", + bindKey: bindKey("Ctrl-Shift-U", "Ctrl-Shift-U"), + exec: function(editor) { editor.toLowerCase(); }, + multiSelectAction: "forEach" +}]; + +}); diff --git a/lib/ace/commands/multi_select_commands.js b/lib/ace/commands/multi_select_commands.js new file mode 100644 index 0000000000..ff59f0458e --- /dev/null +++ b/lib/ace/commands/multi_select_commands.js @@ -0,0 +1,97 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +// commands to enter multiselect mode +exports.defaultCommands = [{ + name: "addCursorAbove", + exec: function(editor) { editor.selectMoreLines(-1); }, + bindKey: {win: "Ctrl-Alt-Up", mac: "Ctrl-Alt-Up"}, + readonly: true +}, { + name: "addCursorBelow", + exec: function(editor) { editor.selectMoreLines(1); }, + bindKey: {win: "Ctrl-Alt-Down", mac: "Ctrl-Alt-Down"}, + readonly: true +}, { + name: "addCursorAboveSkipCurrent", + exec: function(editor) { editor.selectMoreLines(-1, true); }, + bindKey: {win: "Ctrl-Alt-Shift-Up", mac: "Ctrl-Alt-Shift-Up"}, + readonly: true +}, { + name: "addCursorBelowSkipCurrent", + exec: function(editor) { editor.selectMoreLines(1, true); }, + bindKey: {win: "Ctrl-Alt-Shift-Down", mac: "Ctrl-Alt-Shift-Down"}, + readonly: true +}, { + name: "selectMoreBefore", + exec: function(editor) { editor.selectMore(-1); }, + bindKey: {win: "Ctrl-Alt-Left", mac: "Ctrl-Alt-Left"}, + readonly: true +}, { + name: "selectMoreAfter", + exec: function(editor) { editor.selectMore(1); }, + bindKey: {win: "Ctrl-Alt-Right", mac: "Ctrl-Alt-Right"}, + readonly: true +}, { + name: "selectNextBefore", + exec: function(editor) { editor.selectMore(-1, true); }, + bindKey: {win: "Ctrl-Alt-Shift-Left", mac: "Ctrl-Alt-Shift-Left"}, + readonly: true +}, { + name: "selectNextAfter", + exec: function(editor) { editor.selectMore(1, true); }, + bindKey: {win: "Ctrl-Alt-Shift-Right", mac: "Ctrl-Alt-Shift-Right"}, + readonly: true +}, { + name: "splitIntoLines", + exec: function(editor) { editor.multiSelect.splitIntoLines(); }, + bindKey: {win: "Ctrl-Alt-L", mac: "Ctrl-Alt-L"}, + readonly: true +}, { + name: "alignCursors", + exec: function(editor) { editor.alignCursors(); }, + bindKey: {win: "Ctrl-Alt-A", mac: "Ctrl-Alt-A"} +}]; + +// commands active only in multiselect mode +exports.multiSelectCommands = [{ + name: "singleSelection", + bindKey: "esc", + exec: function(editor) { editor.exitMultiSelectMode(); }, + readonly: true, + isAvailable: function(editor) {return editor && editor.inMultiSelectMode} +}]; + +var HashHandler = require("../keyboard/hash_handler").HashHandler; +exports.keyboardHandler = new HashHandler(exports.multiSelectCommands); + +}); diff --git a/lib/ace/config.js b/lib/ace/config.js new file mode 100644 index 0000000000..5a1b0e47c2 --- /dev/null +++ b/lib/ace/config.js @@ -0,0 +1,139 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"no use strict"; + +var lang = require("./lib/lang"); + +var global = (function() { + return this; +})(); + +var options = { + packaged: false, + workerPath: null, + modePath: null, + themePath: null, + basePath: "", + suffix: ".js", + $moduleUrls: {} +}; + +exports.get = function(key) { + if (!options.hasOwnProperty(key)) + throw new Error("Unknown config key: " + key); + + return options[key]; +}; + +exports.set = function(key, value) { + if (!options.hasOwnProperty(key)) + throw new Error("Unknown config key: " + key); + + options[key] = value; +}; + +exports.all = function() { + return lang.copyObject(options); +}; + +exports.moduleUrl = function(name, component) { + if (options.$moduleUrls[name]) + return options.$moduleUrls[name]; + + var parts = name.split("/"); + component = component || parts[parts.length - 2] || ""; + var base = parts[parts.length - 1].replace(component, "").replace(/(^[\-_])|([\-_]$)/, ""); + + if (!base && parts.length > 1) + base = parts[parts.length - 2]; + var path = options[component + "Path"]; + if (path == null) + path = options.basePath; + if (path && path.slice(-1) != "/") + path += "/"; + return path + component + "-" + base + this.get("suffix"); +}; + +exports.setModuleUrl = function(name, subst) { + return options.$moduleUrls[name] = subst; +}; + +exports.init = function() { + options.packaged = require.packaged || module.packaged || (global.define && define.packaged); + + if (!global.document) + return ""; + + var scriptOptions = {}; + var scriptUrl = ""; + + var scripts = document.getElementsByTagName("script"); + for (var i=0; i .ace_gutter-cell { + padding-right: 13px; +} + +.ace_fold-widget { + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + + margin: 0 -12px 0 1px; + display: inline-block; + width: 11px; + vertical-align: top; + + background-image: url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%05%00%00%00%05%08%06%00%00%00%8Do%26%E5%00%00%004IDATx%DAe%8A%B1%0D%000%0C%C2%F2%2CK%96%BC%D0%8F9%81%88H%E9%D0%0E%96%C0%10%92%3E%02%80%5E%82%E4%A9*-%EEsw%C8%CC%11%EE%96w%D8%DC%E9*Eh%0C%151(%00%00%00%00IEND%AEB%60%82"); + background-repeat: no-repeat; + background-position: center; + + border-radius: 3px; + + border: 1px solid transparent; +} + +.ace_fold-widget.ace_end { + background-image: url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%05%00%00%00%05%08%06%00%00%00%8Do%26%E5%00%00%004IDATx%DAm%C7%C1%09%000%08C%D1%8C%ECE%C8E(%8E%EC%02)%1EZJ%F1%C1'%04%07I%E1%E5%EE%CAL%F5%A2%99%99%22%E2%D6%1FU%B5%FE0%D9x%A7%26Wz5%0E%D5%00%00%00%00IEND%AEB%60%82"); +} + +.ace_fold-widget.ace_closed { + background-image: url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%03%00%00%00%06%08%06%00%00%00%06%E5%24%0C%00%00%009IDATx%DA5%CA%C1%09%000%08%03%C0%AC*(%3E%04%C1%0D%BA%B1%23%A4Uh%E0%20%81%C0%CC%F8%82%81%AA%A2%AArGfr%88%08%11%11%1C%DD%7D%E0%EE%5B%F6%F6%CB%B8%05Q%2F%E9tai%D9%00%00%00%00IEND%AEB%60%82"); +} + +.ace_fold-widget:hover { + border: 1px solid rgba(0, 0, 0, 0.3); + background-color: rgba(255, 255, 255, 0.2); + -moz-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7); + -webkit-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7); + box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7); +} + +.ace_fold-widget:active { + border: 1px solid rgba(0, 0, 0, 0.4); + background-color: rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8); + -webkit-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8); + box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8); +} +/** + * Dark version for fold widgets + */ +.ace_dark .ace_fold-widget { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHklEQVQIW2P4//8/AzoGEQ7oGCaLLAhWiSwB146BAQCSTPYocqT0AAAAAElFTkSuQmCC"); +} +.ace_dark .ace_fold-widget.ace_end { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAH0lEQVQIW2P4//8/AxQ7wNjIAjDMgC4AxjCVKBirIAAF0kz2rlhxpAAAAABJRU5ErkJggg=="); +} +.ace_dark .ace_fold-widget.ace_closed { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAHElEQVQIW2P4//+/AxAzgDADlOOAznHAKgPWAwARji8UIDTfQQAAAABJRU5ErkJggg=="); +} +.ace_dark .ace_fold-widget:hover { + box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2); + background-color: rgba(255, 255, 255, 0.1); +} +.ace_dark .ace_fold-widget:active { + -moz-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2); + -webkit-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2); + box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2); +} + + + +.ace_fold-widget.ace_invalid { + background-color: #FFB4B4; + border-color: #DE5555; +} + +.ace_fade-fold-widgets .ace_fold-widget { + -moz-transition: opacity 0.4s ease 0.05s; + -webkit-transition: opacity 0.4s ease 0.05s; + -o-transition: opacity 0.4s ease 0.05s; + -ms-transition: opacity 0.4s ease 0.05s; + transition: opacity 0.4s ease 0.05s; + opacity: 0; +} + +.ace_fade-fold-widgets:hover .ace_fold-widget { + -moz-transition: opacity 0.05s ease 0.05s; + -webkit-transition: opacity 0.05s ease 0.05s; + -o-transition: opacity 0.05s ease 0.05s; + -ms-transition: opacity 0.05s ease 0.05s; + transition: opacity 0.05s ease 0.05s; + opacity:1; +} + +.ace_underline { + text-decoration: underline; +} + +.ace_bold { + font-weight: bold; +} + +.ace_nobold .ace_bold { + font-weight: normal; +} + +.ace_italic { + font-style: italic; +} diff --git a/lib/ace/css/expand-marker.png b/lib/ace/css/expand-marker.png new file mode 100644 index 0000000000..535e81922a Binary files /dev/null and b/lib/ace/css/expand-marker.png differ diff --git a/lib/ace/document.js b/lib/ace/document.js new file mode 100644 index 0000000000..6f1edd05f4 --- /dev/null +++ b/lib/ace/document.js @@ -0,0 +1,634 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("./lib/oop"); +var EventEmitter = require("./lib/event_emitter").EventEmitter; +var Range = require("./range").Range; +var Anchor = require("./anchor").Anchor; + +/** + * class Document + * + * Contains the text of the document. Document can be attached to several [[EditSession `EditSession`]]s. At its core, `Document`s are just an array of strings, with each row in the document matching up to the array index. + * + * + **/ + + /** + * new Document([text]) + * - text (String | Array): The starting text + * + * Creates a new `Document`. If `text` is included, the `Document` contains those strings; otherwise, it's empty. + * + **/ + +var Document = function(text) { + this.$lines = []; + + // There has to be one line at least in the document. If you pass an empty + // string to the insert function, nothing will happen. Workaround. + if (text.length == 0) { + this.$lines = [""]; + } else if (Array.isArray(text)) { + this.insertLines(0, text); + } else { + this.insert({row: 0, column:0}, text); + } +}; + +(function() { + + oop.implement(this, EventEmitter); + + /** + * Document.setValue(text) -> Void + * - text (String): The text to use + * + * Replaces all the lines in the current `Document` with the value of `text`. + **/ + this.setValue = function(text) { + var len = this.getLength(); + this.remove(new Range(0, 0, len, this.getLine(len-1).length)); + this.insert({row: 0, column:0}, text); + }; + + /** + * Document.getValue() -> String + * + * Returns all the lines in the document as a single string, split by the new line character. + **/ + this.getValue = function() { + return this.getAllLines().join(this.getNewLineCharacter()); + }; + + /** + * Document.createAnchor(row, column) -> Anchor + * - row (Number): The row number to use + * - column (Number): The column number to use + * + * Creates a new `Anchor` to define a floating point in the document. + **/ + this.createAnchor = function(row, column) { + return new Anchor(this, row, column); + }; + + /** internal, hide + * Document.$split(text) -> [String] + * - text (String): The text to work with + * + ([String]): A String array, with each index containing a piece of the original `text` string. + * + * Splits a string of text on any newline (`\n`) or carriage-return ('\r') characters. + * + * + **/ + + // check for IE split bug + if ("aaa".split(/a/).length == 0) + this.$split = function(text) { + return text.replace(/\r\n|\r/g, "\n").split("\n"); + } + else + this.$split = function(text) { + return text.split(/\r\n|\r|\n/); + }; + + + /** internal, hide + * Document.$detectNewLine(text) -> Void + * + * + **/ + this.$detectNewLine = function(text) { + var match = text.match(/^.*?(\r\n|\r|\n)/m); + if (match) { + this.$autoNewLine = match[1]; + } else { + this.$autoNewLine = "\n"; + } + }; + + /** + * Document.getNewLineCharacter() -> String + * + (String): If `newLineMode == windows`, `\r\n` is returned.
+ * If `newLineMode == unix`, `\n` is returned.
+ * If `newLineMode == auto`, the value of `autoNewLine` is returned. + * + * Returns the newline character that's being used, depending on the value of `newLineMode`. + * + * + * + **/ + this.getNewLineCharacter = function() { + switch (this.$newLineMode) { + case "windows": + return "\r\n"; + + case "unix": + return "\n"; + + case "auto": + return this.$autoNewLine; + } + }; + + this.$autoNewLine = "\n"; + this.$newLineMode = "auto"; + /** + * Document.setNewLineMode(newLineMode) -> Void + * - newLineMode(String): [The newline mode to use; can be either `windows`, `unix`, or `auto`]{: #Document.setNewLineMode.param} + * + * [Sets the new line mode.]{: #Document.setNewLineMode.desc} + **/ + this.setNewLineMode = function(newLineMode) { + if (this.$newLineMode === newLineMode) + return; + + this.$newLineMode = newLineMode; + }; + + /** + * Document.getNewLineMode() -> String + * + * [Returns the type of newlines being used; either `windows`, `unix`, or `auto`]{: #Document.getNewLineMode} + * + **/ + this.getNewLineMode = function() { + return this.$newLineMode; + }; + + /** + * Document.isNewLine(text) -> Boolean + * - text (String): The text to check + * + * Returns `true` if `text` is a newline character (either `\r\n`, `\r`, or `\n`). + * + **/ + this.isNewLine = function(text) { + return (text == "\r\n" || text == "\r" || text == "\n"); + }; + + /** + * Document.getLine(row) -> String + * - row (Number): The row index to retrieve + * + * Returns a verbatim copy of the given line as it is in the document + * + **/ + this.getLine = function(row) { + return this.$lines[row] || ""; + }; + + /** + * Document.getLines(firstRow, lastRow) -> [String] + * - firstRow (Number): The first row index to retrieve + * - lastRow (Number): The final row index to retrieve + * + * Returns an array of strings of the rows between `firstRow` and `lastRow`. This function is inclusive of `lastRow`. + * + **/ + this.getLines = function(firstRow, lastRow) { + return this.$lines.slice(firstRow, lastRow + 1); + }; + + /** + * Document.getAllLines() -> [String] + * + * Returns all lines in the document as string array. Warning: The caller should not modify this array! + **/ + this.getAllLines = function() { + return this.getLines(0, this.getLength()); + }; + + /** + * Document.getLength() -> Number + * + * Returns the number of rows in the document. + **/ + this.getLength = function() { + return this.$lines.length; + }; + + /** + * Document.getTextRange(range) -> String + * - range (Range): The range to work with + * + * [Given a range within the document, this function returns all the text within that range as a single string.]{: #Document.getTextRange.desc} + **/ + this.getTextRange = function(range) { + if (range.start.row == range.end.row) { + return this.$lines[range.start.row].substring(range.start.column, + range.end.column); + } + else { + var lines = this.getLines(range.start.row+1, range.end.row-1); + lines.unshift((this.$lines[range.start.row] || "").substring(range.start.column)); + lines.push((this.$lines[range.end.row] || "").substring(0, range.end.column)); + return lines.join(this.getNewLineCharacter()); + } + }; + + /** internal, hide + * Document.$clipPosition(position) -> Number + * + * + **/ + this.$clipPosition = function(position) { + var length = this.getLength(); + if (position.row >= length) { + position.row = Math.max(0, length - 1); + position.column = this.getLine(length-1).length; + } + return position; + }; + + /** + * Document.insert(position, text) -> Number + * - position (Number): The position to start inserting at + * - text (String): A chunk of text to insert + * + (Number): The position of the last line of `text`. If the length of `text` is 0, this function simply returns `position`. + * Inserts a block of `text` and the indicated `position`. + * + * + **/ + this.insert = function(position, text) { + if (!text || text.length === 0) + return position; + + position = this.$clipPosition(position); + + // only detect new lines if the document has no line break yet + if (this.getLength() <= 1) + this.$detectNewLine(text); + + var lines = this.$split(text); + var firstLine = lines.splice(0, 1)[0]; + var lastLine = lines.length == 0 ? null : lines.splice(lines.length - 1, 1)[0]; + + position = this.insertInLine(position, firstLine); + if (lastLine !== null) { + position = this.insertNewLine(position); // terminate first line + position = this.insertLines(position.row, lines); + position = this.insertInLine(position, lastLine || ""); + } + return position; + }; + + /** + * Document.insertLines(row, lines) -> Object + * - row (Number): The index of the row to insert at + * - lines (Array): An array of strings + * + (Object): Returns an object containing the final row and column, like this:
+ * ```{row: endRow, column: 0}```
+ * If `lines` is empty, this function returns an object containing the current row, and column, like this:
+ * ```{row: row, column: 0}``` + * + * Inserts the elements in `lines` into the document, starting at the row index given by `row`. This method also triggers the `'change'` event. + * + * + **/ + /** + * Document@change(e) + * - e (Object): Contains at least one property called `"action"`. `"action"` indicates the action that triggered the change. Each action also has a set of additional properties. + * + * Fires whenever the document changes. + * + * Several methods trigger different `"change"` events. Below is a list of each action type, followed by each property that's also available: + * + * * `"insertLines"` (emitted by [[Document.insertLines]]) + * * `range`: the [[Range]] of the change within the document + * * `lines`: the lines in the document that are changing + * * `"insertText"` (emitted by [[Document.insertNewLine]]) + * * `range`: the [[Range]] of the change within the document + * * `text`: the text that's being added + * * `"removeLines"` (emitted by [[Document.insertLines]]) + * * `range`: the [[Range]] of the change within the document + * * `lines`: the lines in the document that were removed + * * `nl`: the new line character (as defined by [[Document.getNewLineCharacter]]) + * * `"removeText"` (emitted by [[Document.removeInLine]] and [[Document.removeNewLine]]) + * * `range`: the [[Range]] of the change within the document + * * `text`: the text that's being removed + * + **/ + this.insertLines = function(row, lines) { + if (lines.length == 0) + return {row: row, column: 0}; + + // apply doesn't work for big arrays (smallest threshold is on safari 0xFFFF) + // to circumvent that we have to break huge inserts into smaller chunks here + if (lines.length > 0xFFFF) { + var end = this.insertLines(row, lines.slice(0xFFFF)); + lines = lines.slice(0, 0xFFFF); + } + + var args = [row, 0]; + args.push.apply(args, lines); + this.$lines.splice.apply(this.$lines, args); + + var range = new Range(row, 0, row + lines.length, 0); + var delta = { + action: "insertLines", + range: range, + lines: lines + }; + this._emit("change", { data: delta }); + return end || range.end; + }; + + /** + * Document.insertNewLine(position) -> Object + * - position (String): The position to insert at + * + (Object): Returns an object containing the final row and column, like this:
+ * ```{row: endRow, column: 0}``` + * + * Inserts a new line into the document at the current row's `position`. This method also triggers the `'change'` event. + * + * + * + **/ + this.insertNewLine = function(position) { + position = this.$clipPosition(position); + var line = this.$lines[position.row] || ""; + + this.$lines[position.row] = line.substring(0, position.column); + this.$lines.splice(position.row + 1, 0, line.substring(position.column, line.length)); + + var end = { + row : position.row + 1, + column : 0 + }; + + var delta = { + action: "insertText", + range: Range.fromPoints(position, end), + text: this.getNewLineCharacter() + }; + this._emit("change", { data: delta }); + + return end; + }; + + /** + * Document.insertInLine(position, text) -> Object | Number + * - position (Number): The position to insert at + * - text (String): A chunk of text + * + (Object): Returns an object containing the final row and column, like this:
+ * ```{row: endRow, column: 0}``` + * + (Number): If `text` is empty, this function returns the value of `position` + * + * Inserts `text` into the `position` at the current row. This method also triggers the `'change'` event. + * + * + * + **/ + this.insertInLine = function(position, text) { + if (text.length == 0) + return position; + + var line = this.$lines[position.row] || ""; + + this.$lines[position.row] = line.substring(0, position.column) + text + + line.substring(position.column); + + var end = { + row : position.row, + column : position.column + text.length + }; + + var delta = { + action: "insertText", + range: Range.fromPoints(position, end), + text: text + }; + this._emit("change", { data: delta }); + + return end; + }; + + /** + * Document.remove(range) -> Object + * - range (Range): A specified Range to remove + * + (Object): Returns the new `start` property of the range, which contains `startRow` and `startColumn`. If `range` is empty, this function returns the unmodified value of `range.start`. + * + * Removes the `range` from the document. + * + * + **/ + this.remove = function(range) { + // clip to document + range.start = this.$clipPosition(range.start); + range.end = this.$clipPosition(range.end); + + if (range.isEmpty()) + return range.start; + + var firstRow = range.start.row; + var lastRow = range.end.row; + + if (range.isMultiLine()) { + var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1; + var lastFullRow = lastRow - 1; + + if (range.end.column > 0) + this.removeInLine(lastRow, 0, range.end.column); + + if (lastFullRow >= firstFullRow) + this.removeLines(firstFullRow, lastFullRow); + + if (firstFullRow != firstRow) { + this.removeInLine(firstRow, range.start.column, this.getLine(firstRow).length); + this.removeNewLine(range.start.row); + } + } + else { + this.removeInLine(firstRow, range.start.column, range.end.column); + } + return range.start; + }; + + /** + * Document.removeInLine(row, startColumn, endColumn) -> Object + * - row (Number): The row to remove from + * - startColumn (Number): The column to start removing at + * - endColumn (Number): The column to stop removing at + * + (Object): Returns an object containing `startRow` and `startColumn`, indicating the new row and column values.
If `startColumn` is equal to `endColumn`, this function returns nothing. + * + * Removes the specified columns from the `row`. This method also triggers the `'change'` event. + * + * + **/ + this.removeInLine = function(row, startColumn, endColumn) { + if (startColumn == endColumn) + return; + + var range = new Range(row, startColumn, row, endColumn); + var line = this.getLine(row); + var removed = line.substring(startColumn, endColumn); + var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length); + this.$lines.splice(row, 1, newLine); + + var delta = { + action: "removeText", + range: range, + text: removed + }; + this._emit("change", { data: delta }); + return range.start; + }; + + /** + * Document.removeLines(firstRow, lastRow) -> [String] + * - firstRow (Number): The first row to be removed + * - lastRow (Number): The last row to be removed + * + ([String]): Returns all the removed lines. + * + * Removes a range of full lines. This method also triggers the `'change'` event. + * + * + **/ + this.removeLines = function(firstRow, lastRow) { + var range = new Range(firstRow, 0, lastRow + 1, 0); + var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1); + + var delta = { + action: "removeLines", + range: range, + nl: this.getNewLineCharacter(), + lines: removed + }; + this._emit("change", { data: delta }); + return removed; + }; + + /** + * Document.removeNewLine(row) -> Void + * - row (Number): The row to check + * + * Removes the new line between `row` and the row immediately following it. This method also triggers the `'change'` event. + * + **/ + this.removeNewLine = function(row) { + var firstLine = this.getLine(row); + var secondLine = this.getLine(row+1); + + var range = new Range(row, firstLine.length, row+1, 0); + var line = firstLine + secondLine; + + this.$lines.splice(row, 2, line); + + var delta = { + action: "removeText", + range: range, + text: this.getNewLineCharacter() + }; + this._emit("change", { data: delta }); + }; + + /** + * Document.replace(range, text) -> Object + * - range (Range): A specified Range to replace + * - text (String): The new text to use as a replacement + * + (Object): Returns an object containing the final row and column, like this: + * {row: endRow, column: 0} + * If the text and range are empty, this function returns an object containing the current `range.start` value. + * If the text is the exact same as what currently exists, this function returns an object containing the current `range.end` value. + * + * Replaces a range in the document with the new `text`. + * + **/ + this.replace = function(range, text) { + if (text.length == 0 && range.isEmpty()) + return range.start; + + // Shortcut: If the text we want to insert is the same as it is already + // in the document, we don't have to replace anything. + if (text == this.getTextRange(range)) + return range.end; + + this.remove(range); + if (text) { + var end = this.insert(range.start, text); + } + else { + end = range.start; + } + + return end; + }; + + /** + * Document.applyDeltas(deltas) -> Void + * + * Applies all the changes previously accumulated. These can be either `'includeText'`, `'insertLines'`, `'removeText'`, and `'removeLines'`. + **/ + this.applyDeltas = function(deltas) { + for (var i=0; i Void + * + * Reverts any changes previously applied. These can be either `'includeText'`, `'insertLines'`, `'removeText'`, and `'removeLines'`. + **/ + this.revertDeltas = function(deltas) { + for (var i=deltas.length-1; i>=0; i--) { + var delta = deltas[i]; + + var range = Range.fromPoints(delta.range.start, delta.range.end); + + if (delta.action == "insertLines") + this.removeLines(range.start.row, range.end.row - 1); + else if (delta.action == "insertText") + this.remove(range); + else if (delta.action == "removeLines") + this.insertLines(range.start.row, delta.lines); + else if (delta.action == "removeText") + this.insert(range.start, delta.text); + } + }; + +}).call(Document.prototype); + +exports.Document = Document; +}); diff --git a/lib/ace/document_test.js b/lib/ace/document_test.js new file mode 100644 index 0000000000..5c324db0fe --- /dev/null +++ b/lib/ace/document_test.js @@ -0,0 +1,306 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); + require("./test/mockdom"); +} + +define(function(require, exports, module) { +"use strict"; + +var Document = require("./document").Document; +var Range = require("./range").Range; +var assert = require("./test/assertions"); + +module.exports = { + + "test: insert text in line" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.insert({row: 0, column: 1}, "juhu"); + assert.equal(doc.getValue(), ["1juhu2", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["1juhu2", "34"].join("\n")); + }, + + "test: insert new line" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.insertNewLine({row: 0, column: 1}); + assert.equal(doc.getValue(), ["1", "2", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["1", "2", "34"].join("\n")); + }, + + "test: insert lines at the beginning" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.insertLines(0, ["aa", "bb"]); + assert.equal(doc.getValue(), ["aa", "bb", "12", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["aa", "bb", "12", "34"].join("\n")); + }, + + "test: insert lines at the end" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.insertLines(2, ["aa", "bb"]); + assert.equal(doc.getValue(), ["12", "34", "aa", "bb"].join("\n")); + }, + + "test: insert lines in the middle" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.insertLines(1, ["aa", "bb"]); + assert.equal(doc.getValue(), ["12", "aa", "bb", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["12", "aa", "bb", "34"].join("\n")); + }, + + "test: insert multi line string at the start" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.insert({row: 0, column: 0}, "aa\nbb\ncc"); + assert.equal(doc.getValue(), ["aa", "bb", "cc12", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["aa", "bb", "cc12", "34"].join("\n")); + }, + + "test: insert multi line string at the end" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.insert({row: 2, column: 0}, "aa\nbb\ncc"); + assert.equal(doc.getValue(), ["12", "34aa", "bb", "cc"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["12", "34aa", "bb", "cc"].join("\n")); + }, + + "test: insert multi line string in the middle" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.insert({row: 0, column: 1}, "aa\nbb\ncc"); + assert.equal(doc.getValue(), ["1aa", "bb", "cc2", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["1aa", "bb", "cc2", "34"].join("\n")); + }, + + "test: delete in line" : function() { + var doc = new Document(["1234", "5678"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.remove(new Range(0, 1, 0, 3)); + assert.equal(doc.getValue(), ["14", "5678"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["1234", "5678"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["14", "5678"].join("\n")); + }, + + "test: delete new line" : function() { + var doc = new Document(["1234", "5678"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.remove(new Range(0, 4, 1, 0)); + assert.equal(doc.getValue(), ["12345678"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["1234", "5678"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["12345678"].join("\n")); + }, + + "test: delete multi line range line" : function() { + var doc = new Document(["1234", "5678", "abcd"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.remove(new Range(0, 2, 2, 2)); + assert.equal(doc.getValue(), ["12cd"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["1234", "5678", "abcd"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["12cd"].join("\n")); + }, + + "test: delete full lines" : function() { + var doc = new Document(["1234", "5678", "abcd"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.remove(new Range(1, 0, 3, 0)); + assert.equal(doc.getValue(), ["1234", ""].join("\n")); + }, + + "test: remove lines should return the removed lines" : function() { + var doc = new Document(["1234", "5678", "abcd"]); + + var removed = doc.removeLines(1, 2); + assert.equal(removed.join("\n"), ["5678", "abcd"].join("\n")); + }, + + "test: should handle unix style new lines" : function() { + var doc = new Document(["1", "2", "3"]); + assert.equal(doc.getValue(), ["1", "2", "3"].join("\n")); + }, + + "test: should handle windows style new lines" : function() { + var doc = new Document(["1", "2", "3"].join("\r\n")); + + doc.setNewLineMode("unix"); + assert.equal(doc.getValue(), ["1", "2", "3"].join("\n")); + }, + + "test: set new line mode to 'windows' should use '\\r\\n' as new lines": function() { + var doc = new Document(["1", "2", "3"].join("\n")); + doc.setNewLineMode("windows"); + assert.equal(doc.getValue(), ["1", "2", "3"].join("\r\n")); + }, + + "test: set new line mode to 'unix' should use '\\n' as new lines": function() { + var doc = new Document(["1", "2", "3"].join("\r\n")); + + doc.setNewLineMode("unix"); + assert.equal(doc.getValue(), ["1", "2", "3"].join("\n")); + }, + + "test: set new line mode to 'auto' should detect the incoming nl type": function() { + var doc = new Document(["1", "2", "3"].join("\n")); + + doc.setNewLineMode("auto"); + assert.equal(doc.getValue(), ["1", "2", "3"].join("\n")); + + var doc = new Document(["1", "2", "3"].join("\r\n")); + + doc.setNewLineMode("auto"); + assert.equal(doc.getValue(), ["1", "2", "3"].join("\r\n")); + + doc.replace(new Range(0, 0, 2, 1), ["4", "5", "6"].join("\n")); + assert.equal(["4", "5", "6"].join("\n"), doc.getValue()); + }, + + "test: set value": function() { + var doc = new Document("1"); + assert.equal("1", doc.getValue()); + + doc.setValue(doc.getValue()); + assert.equal("1", doc.getValue()); + + var doc = new Document("1\n2"); + assert.equal("1\n2", doc.getValue()); + + doc.setValue(doc.getValue()); + assert.equal("1\n2", doc.getValue()); + }, + + "test: empty document has to contain one line": function() { + var doc = new Document(""); + assert.equal(doc.$lines.length, 1); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec() +} diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js new file mode 100644 index 0000000000..dffcd73ddb --- /dev/null +++ b/lib/ace/edit_session.js @@ -0,0 +1,2517 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var config = require("./config"); +var oop = require("./lib/oop"); +var lang = require("./lib/lang"); +var net = require("./lib/net"); +var EventEmitter = require("./lib/event_emitter").EventEmitter; +var Selection = require("./selection").Selection; +var TextMode = require("./mode/text").Mode; +var Range = require("./range").Range; +var Document = require("./document").Document; +var BackgroundTokenizer = require("./background_tokenizer").BackgroundTokenizer; +var SearchHighlight = require("./search_highlight").SearchHighlight; + +/** + * class EditSession + * + * Stores all the data about [[Editor `Editor`]] state providing easy way to change editors state. `EditSession` can be attached to only one [[Document `Document`]]. Same `Document` can be attached to several `EditSession`s. + * + **/ + +// events +/** + * EditSession@change(e) + * - e (Object): An object containing a `delta` of information about the change. + * + * Emitted when the document changes. + **/ +/** + * EditSession@changeTabSize() + * + * Emitted when the tab size changes, via [[EditSession.setTabSize]]. + **/ +/** + * EditSession@changeOverwrite() + * + * Emitted when the ability to overwrite text changes, via [[EditSession.setOverwrite]]. + **/ +/** + * EditSession@changeBreakpoint() + * + * Emitted when the gutter changes, either by setting or removing breakpoints, or when the gutter decorations change. + **/ +/** + * EditSession@changeFrontMarker() + * + * Emitted when a front marker changes. + **/ +/** + * EditSession@changeBackMarker() + * + * Emitted when a back marker changes. + **/ +/** + * EditSession@changeAnnotation() + * + * Emitted when an annotation changes, like through [[EditSession.setAnnotations]]. + **/ +/** + * EditSession@tokenizerUpdate(e) + * - e (Object): An object containing one property, `"data"`, that contains information about the changing rows + * + * Emitted when a background tokenizer asynchronously processes new rows. + * + **/ +/** hide + * EditSession@loadMode(e) + * + * + * + **/ +/** + * EditSession@changeMode() + * + * Emitted when the current mode changes. + * + **/ +/** + * EditSession@changeWrapMode() + * + * Emitted when the wrap mode changes. + * + **/ +/** + * EditSession@changeWrapLimit() + * + * Emitted when the wrapping limit changes. + * + **/ +/** + * EditSession@changeFold(e) + * + * Emitted when a code fold is added or removed. + * + **/ + /** + * EditSession@changeScrollTop(scrollTop) + * - scrollTop (Number): The new scroll top value + * + * Emitted when the scroll top changes. + **/ +/** + * EditSession@changeScrollLeft(scrollLeft) + * - scrollLeft (Number): The new scroll left value + * + * Emitted when the scroll left changes. + **/ + + +/** + * new EditSession(text, mode) + * - text (Document | String): If `text` is a `Document`, it associates the `EditSession` with it. Otherwise, a new `Document` is created, with the initial text + * - mode (TextMode): The inital language mode to use for the document + * + * Sets up a new `EditSession` and associates it with the given `Document` and `TextMode`. + * + **/ + +var EditSession = function(text, mode) { + this.$breakpoints = []; + this.$decorations = []; + this.$frontMarkers = {}; + this.$backMarkers = {}; + this.$markerId = 1; + this.$undoSelect = true; + + this.$foldData = []; + this.$foldData.toString = function() { + var str = ""; + this.forEach(function(foldLine) { + str += "\n" + foldLine.toString(); + }); + return str; + } + this.on("changeFold", this.onChangeFold.bind(this)); + this.$onChange = this.onChange.bind(this); + + if (typeof text != "object" || !text.getLine) + text = new Document(text); + + this.setDocument(text); + + this.selection = new Selection(this); + this.setMode(mode); +}; + + +(function() { + + oop.implement(this, EventEmitter); + + /** + * EditSession.setDocument(doc) + * - doc (Document): The new `Document` to use + * + * Sets the `EditSession` to point to a new `Document`. If a `BackgroundTokenizer` exists, it also points to `doc`. + * + **/ + this.setDocument = function(doc) { + if (this.doc) + this.doc.removeListener("change", this.$onChange); + + this.doc = doc; + doc.on("change", this.$onChange); + + if (this.bgTokenizer) + this.bgTokenizer.setDocument(this.getDocument()); + + this.resetCaches(); + }; + + /** + * EditSession.getDocument() -> Document + * + * Returns the `Document` associated with this session. + * + **/ + this.getDocument = function() { + return this.doc; + }; + + /** internal, hide + * EditSession.$resetRowCache(row) + * - row (Number): The row to work with + * + * + * + **/ + this.$resetRowCache = function(docRow) { + if (!docRow) { + this.$docRowCache = []; + this.$screenRowCache = []; + return; + } + + var i = this.$getRowCacheIndex(this.$docRowCache, docRow) + 1; + var l = this.$docRowCache.length; + this.$docRowCache.splice(i, l); + this.$screenRowCache.splice(i, l); + + }; + + this.$getRowCacheIndex = function(cacheArray, val) { + var low = 0; + var hi = cacheArray.length - 1; + + while (low <= hi) { + var mid = (low + hi) >> 1; + var c = cacheArray[mid]; + + if (val > c) + low = mid + 1; + else if (val < c) + hi = mid - 1; + else + return mid; + } + + return low && low -1; + }; + + this.resetCaches = function() { + this.$modified = true; + this.$wrapData = []; + this.$rowLengthCache = []; + this.$resetRowCache(0); + if (this.bgTokenizer) + this.bgTokenizer.start(0); + }; + + this.onChangeFold = function(e) { + var fold = e.data; + this.$resetRowCache(fold.start.row); + }; + + this.onChange = function(e) { + var delta = e.data; + this.$modified = true; + + this.$resetRowCache(delta.range.start.row); + + var removedFolds = this.$updateInternalDataOnChange(e); + if (!this.$fromUndo && this.$undoManager && !delta.ignore) { + this.$deltasDoc.push(delta); + if (removedFolds && removedFolds.length != 0) { + this.$deltasFold.push({ + action: "removeFolds", + folds: removedFolds + }); + } + + this.$informUndoManager.schedule(); + } + + this.bgTokenizer.$updateOnChange(delta); + this._emit("change", e); + }; + + /** + * EditSession.setValue(text) + * - text (String): The new text to place + * + * Sets the session text. + * + **/ + this.setValue = function(text) { + this.doc.setValue(text); + this.selection.moveCursorTo(0, 0); + this.selection.clearSelection(); + + this.$resetRowCache(0); + this.$deltas = []; + this.$deltasDoc = []; + this.$deltasFold = []; + this.getUndoManager().reset(); + }; + + /** alias of: EditSession.toString + * EditSession.getValue() -> String + * + * Returns the current [[Document `Document`]] as a string. + * + **/ + /** alias of: EditSession.getValue + * EditSession.toString() -> String + * + * Returns the current [[Document `Document`]] as a string. + * + **/ + this.getValue = + this.toString = function() { + return this.doc.getValue(); + }; + + /** + * EditSession.getSelection() -> Selection + * + * Returns the string of the current selection. + **/ + this.getSelection = function() { + return this.selection; + }; + + /** related to: BackgroundTokenizer.getState + * EditSession.getState(row) -> Array + * - row (Number): The row to start at + * + * {:BackgroundTokenizer.getState} + * + **/ + this.getState = function(row) { + return this.bgTokenizer.getState(row); + }; + + /** related to: BackgroundTokenizer.getTokens + * EditSession.getTokens(row) -> Array + * - row (Number): The row to start at + * + * Starts tokenizing at the row indicated. Returns a list of objects of the tokenized rows. + * + **/ + this.getTokens = function(row) { + return this.bgTokenizer.getTokens(row); + }; + + /** + * EditSession.getTokenAt(row, column) -> Object + * - row (Number): The row number to retrieve from + * - column (Number): The column number to retrieve from + * + * Returns an object indicating the token at the current row. The object has two properties: `index` and `start`. + **/ + this.getTokenAt = function(row, column) { + var tokens = this.bgTokenizer.getTokens(row); + var token, c = 0; + if (column == null) { + i = tokens.length - 1; + c = this.getLine(row).length; + } else { + for (var i = 0; i < tokens.length; i++) { + c += tokens[i].value.length; + if (c >= column) + break; + } + } + token = tokens[i]; + if (!token) + return null; + token.index = i; + token.start = c - token.value.length; + return token; + }; + + /** + * EditSession.setUndoManager(undoManager) + * - undoManager (UndoManager): The new undo manager + * + * Sets the undo manager. + **/ + this.setUndoManager = function(undoManager) { + this.$undoManager = undoManager; + this.$deltas = []; + this.$deltasDoc = []; + this.$deltasFold = []; + + if (this.$informUndoManager) + this.$informUndoManager.cancel(); + + if (undoManager) { + var self = this; + /** internal, hide + * EditSession.$syncInformUndoManager() + * + * + **/ + this.$syncInformUndoManager = function() { + self.$informUndoManager.cancel(); + + if (self.$deltasFold.length) { + self.$deltas.push({ + group: "fold", + deltas: self.$deltasFold + }); + self.$deltasFold = []; + } + + if (self.$deltasDoc.length) { + self.$deltas.push({ + group: "doc", + deltas: self.$deltasDoc + }); + self.$deltasDoc = []; + } + + if (self.$deltas.length > 0) { + undoManager.execute({ + action: "aceupdate", + args: [self.$deltas, self] + }); + } + + self.$deltas = []; + } + this.$informUndoManager = + lang.deferredCall(this.$syncInformUndoManager); + } + }; + + this.$defaultUndoManager = { + undo: function() {}, + redo: function() {}, + reset: function() {} + }; + + /** + * EditSession.getUndoManager() -> UndoManager + * + * Returns the current undo manager. + **/ + this.getUndoManager = function() { + return this.$undoManager || this.$defaultUndoManager; + }, + + /** + * EditSession.getTabString() -> String + * + * Returns the current value for tabs. If the user is using soft tabs, this will be a series of spaces (defined by [[EditSession.getTabSize `getTabSize()`]]); otherwise it's simply `'\t'`. + **/ + this.getTabString = function() { + if (this.getUseSoftTabs()) { + return lang.stringRepeat(" ", this.getTabSize()); + } else { + return "\t"; + } + }; + + this.$useSoftTabs = true; + /** + * EditSession.setUseSoftTabs(useSoftTabs) + * - useSoftTabs (Boolean): Value indicating whether or not to use soft tabs + * + * Pass `true` to enable the use of soft tabs. Soft tabs means you're using spaces instead of the tab character (`'\t'`). + * + **/ + this.setUseSoftTabs = function(useSoftTabs) { + if (this.$useSoftTabs === useSoftTabs) return; + + this.$useSoftTabs = useSoftTabs; + }; + + /** + * EditSession.getUseSoftTabs() -> Boolean + * + * Returns `true` if soft tabs are being used, `false` otherwise. + * + **/ + this.getUseSoftTabs = function() { + return this.$useSoftTabs; + }; + + this.$tabSize = 4; + /** + * EditSession.setTabSize(tabSize) + * - tabSize (Number): The new tab size + * + * Set the number of spaces that define a soft tab; for example, passing in `4` transforms the soft tabs to be equivalent to four spaces. This function also emits the `changeTabSize` event. + **/ + this.setTabSize = function(tabSize) { + if (isNaN(tabSize) || this.$tabSize === tabSize) return; + + this.$modified = true; + this.$rowLengthCache = []; + this.$tabSize = tabSize; + this._emit("changeTabSize"); + }; + + /** + * EditSession.getTabSize() -> Number + * + * Returns the current tab size. + **/ + this.getTabSize = function() { + return this.$tabSize; + }; + + /** + * EditSession.isTabStop(position) -> Boolean + * - position (Object): The position to check + * + * Returns `true` if the character at the position is a soft tab. + **/ + this.isTabStop = function(position) { + return this.$useSoftTabs && (position.column % this.$tabSize == 0); + }; + + this.$overwrite = false; + /** + * EditSession.setOverwrite(overwrite) + * - overwrite (Boolean): Defines wheter or not to set overwrites + * + * Pass in `true` to enable overwrites in your session, or `false` to disable. + * + * If overwrites is enabled, any text you enter will type over any text after it. If the value of `overwrite` changes, this function also emites the `changeOverwrite` event. + * + **/ + this.setOverwrite = function(overwrite) { + if (this.$overwrite == overwrite) return; + + this.$overwrite = overwrite; + this._emit("changeOverwrite"); + }; + + /** + * EditSession.getOverwrite() -> Boolean + * + * Returns `true` if overwrites are enabled; `false` otherwise. + **/ + this.getOverwrite = function() { + return this.$overwrite; + }; + + /** + * EditSession.toggleOverwrite() + * + * Sets the value of overwrite to the opposite of whatever it currently is. + **/ + this.toggleOverwrite = function() { + this.setOverwrite(!this.$overwrite); + }; + + /** + * EditSession.addGutterDecoration(row, className) -> Void + * - row (Number): The row number + * - className (String): The class to add + * + * Adds `className` to the `row`, to be used for CSS stylings and whatnot. + **/ + this.addGutterDecoration = function(row, className) { + if (!this.$decorations[row]) + this.$decorations[row] = ""; + this.$decorations[row] += " " + className; + this._emit("changeBreakpoint", {}); + }; + + /** + * EditSession.removeGutterDecoration(row, className)-> Void + * - row (Number): The row number + * - className (String): The class to add + * + * Removes `className` from the `row`. + **/ + this.removeGutterDecoration = function(row, className) { + this.$decorations[row] = (this.$decorations[row] || "").replace(" " + className, ""); + this._emit("changeBreakpoint", {}); + }; + + /** + * EditSession.getBreakpoints() -> Array + * + * Returns an array of numbers, indicating which rows have breakpoints. + **/ + this.getBreakpoints = function() { + return this.$breakpoints; + }; + + /** + * EditSession.setBreakpoints(rows) + * - rows (Array): An array of row indicies + * + * Sets a breakpoint on every row number given by `rows`. This function also emites the `'changeBreakpoint'` event. + * + **/ + this.setBreakpoints = function(rows) { + this.$breakpoints = []; + for (var i=0; i Number + * - range (Range): Define the range of the marker + * - clazz (String): Set the CSS class for the marker + * - type (Function | String): Identify the type of the marker + * - inFront (Boolean): Set to `true` to establish a front marker + * + * Adds a new marker to the given `Range`. If `inFront` is `true`, a front marker is defined, and the `'changeFrontMarker'` event fires; otherwise, the `'changeBackMarker'` event fires. + * + **/ + this.addMarker = function(range, clazz, type, inFront) { + var id = this.$markerId++; + + var marker = { + range : range, + type : type || "line", + renderer: typeof type == "function" ? type : null, + clazz : clazz, + inFront: !!inFront, + id: id + } + + if (inFront) { + this.$frontMarkers[id] = marker; + this._emit("changeFrontMarker") + } else { + this.$backMarkers[id] = marker; + this._emit("changeBackMarker") + } + + return id; + }; + + /** + * EditSession.addDynamicMarker(marker, inFront) -> Object + * - marker (Object): object with update method + * - inFront (Boolean): Set to `true` to establish a front marker + * + * Adds a dynamic marker to the session. + **/ + this.addDynamicMarker = function(marker, inFront) { + if (!marker.update) + return; + var id = this.$markerId++; + marker.id = id; + marker.inFront = !!inFront; + + if (inFront) { + this.$frontMarkers[id] = marker; + this._emit("changeFrontMarker") + } else { + this.$backMarkers[id] = marker; + this._emit("changeBackMarker") + } + + return marker; + }; + + /** + * EditSession.removeMarker(markerId) + * - markerId (Number): A number representing a marker + * + * Removes the marker with the specified ID. If this marker was in front, the `'changeFrontMarker'` event is emitted. If the marker was in the back, the `'changeBackMarker'` event is emitted. + * + **/ + this.removeMarker = function(markerId) { + var marker = this.$frontMarkers[markerId] || this.$backMarkers[markerId]; + if (!marker) + return; + + var markers = marker.inFront ? this.$frontMarkers : this.$backMarkers; + if (marker) { + delete (markers[markerId]); + this._emit(marker.inFront ? "changeFrontMarker" : "changeBackMarker"); + } + }; + + /** + * EditSession.getMarkers(inFront) -> Array + * - inFront (Boolean): If `true`, indicates you only want front markers; `false` indicates only back markers + * + * Returns an array containing the IDs of all the markers, either front or back. + * + **/ + this.getMarkers = function(inFront) { + return inFront ? this.$frontMarkers : this.$backMarkers; + }; + + this.highlight = function(re) { + if (!this.$searchHighlight) { + var highlight = new SearchHighlight(null, "ace_selected-word", "text"); + this.$searchHighlight = this.addDynamicMarker(highlight); + } + this.$searchHighlight.setRegexp(re); + } + + // experimental + this.highlightLines = function(startRow, endRow, clazz, inFront) { + if (typeof endRow != "number") { + clazz = endRow; + endRow = startRow; + } + if (!clazz) + clazz = "ace_step"; + + var range = new Range(startRow, 0, endRow, Infinity); + + var id = this.addMarker(range, clazz, "fullLine", inFront); + range.id = id; + return range; + }, + + /* + * Error: + * { + * row: 12, + * column: 2, //can be undefined + * text: "Missing argument", + * type: "error" // or "warning" or "info" + * } + */ + /** + * EditSession.setAnnotations(annotations) + * - annotations (Array): A list of annotations + * + * Sets annotations for the `EditSession`. This functions emits the `'changeAnnotation'` event. + **/ + this.setAnnotations = function(annotations) { + this.$annotations = annotations; + this._emit("changeAnnotation", {}); + }; + + /** + * EditSession.getAnnotations() -> Object + * + * Returns the annotations for the `EditSession`. + **/ + this.getAnnotations = function() { + return this.$annotations || []; + }; + + /** + * EditSession.clearAnnotations() + * + * Clears all the annotations for this session. This function also triggers the `'changeAnnotation'` event. + **/ + this.clearAnnotations = function() { + this.$annotations = {}; + this._emit("changeAnnotation", {}); + }; + + /** internal, hide + * EditSession.$detectNewLine(text) + * - text (String): A block of text + * + * If `text` contains either the newline (`\n`) or carriage-return ('\r') characters, `$autoNewLine` stores that value. + * + **/ + this.$detectNewLine = function(text) { + var match = text.match(/^.*?(\r?\n)/m); + if (match) { + this.$autoNewLine = match[1]; + } else { + this.$autoNewLine = "\n"; + } + }; + + /** + * EditSession.getWordRange(row, column) -> Range + * - row (Number): The row to start at + * - column (Number): The column to start at + * + * Given a starting row and column, this method returns the `Range` of the first word boundary it finds. + * + **/ + this.getWordRange = function(row, column) { + var line = this.getLine(row); + + var inToken = false; + if (column > 0) + inToken = !!line.charAt(column - 1).match(this.tokenRe); + + if (!inToken) + inToken = !!line.charAt(column).match(this.tokenRe); + + if (inToken) + var re = this.tokenRe; + else if (/^\s+$/.test(line.slice(column-1, column+1))) + var re = /\s/; + else + var re = this.nonTokenRe; + + var start = column; + if (start > 0) { + do { + start--; + } + while (start >= 0 && line.charAt(start).match(re)); + start++; + } + + var end = column; + while (end < line.length && line.charAt(end).match(re)) { + end++; + } + + return new Range(row, start, row, end); + }; + + /** + * EditSession.getAWordRange(row, column) -> Range + * - row (Number): The row number to start from + * - column (Number): The column number to start from + * + * Gets the range of a word, including its right whitespace. + **/ + this.getAWordRange = function(row, column) { + var wordRange = this.getWordRange(row, column); + var line = this.getLine(wordRange.end.row); + + while (line.charAt(wordRange.end.column).match(/[ \t]/)) { + wordRange.end.column += 1; + } + return wordRange; + }; + + /** related to: Document.setNewLineMode + * EditSession.setNewLineMode(newLineMode) + * - newLineMode (String): {:Document.setNewLineMode.param} + * + * {:Document.setNewLineMode.desc} + **/ + this.setNewLineMode = function(newLineMode) { + this.doc.setNewLineMode(newLineMode); + }; + + /** related to: Document.getNewLineMode + * EditSession.getNewLineMode() -> String + * + * Returns the current new line mode. + **/ + this.getNewLineMode = function() { + return this.doc.getNewLineMode(); + }; + + this.$useWorker = true; + + /** + * EditSession.setUseWorker(useWorker) + * - useWorker (Boolean): Set to `true` to use a worker + * + * Identifies if you want to use a worker for the `EditSession`. + * + **/ + this.setUseWorker = function(useWorker) { + if (this.$useWorker == useWorker) + return; + + this.$useWorker = useWorker; + + this.$stopWorker(); + if (useWorker) + this.$startWorker(); + }; + + /** + * EditSession.getUseWorker() -> Boolean + * + * Returns `true` if workers are being used. + **/ + this.getUseWorker = function() { + return this.$useWorker; + }; + + /** + * EditSession.onReloadTokenizer(e) + * + * Reloads all the tokens on the current session. This function calls [[BackgroundTokenizer.start `BackgroundTokenizer.start ()`]] to all the rows; it also emits the `'tokenizerUpdate'` event. + **/ + this.onReloadTokenizer = function(e) { + var rows = e.data; + this.bgTokenizer.start(rows.first); + this._emit("tokenizerUpdate", e); + }; + + this.$modes = {}; + this._loadMode = function(mode, callback) { + if (!this.$modes["null"]) + this.$modes["null"] = this.$modes["ace/mode/text"] = new TextMode(); + + if (this.$modes[mode]) + return callback(this.$modes[mode]); + + var _self = this; + var module; + try { + module = require(mode); + } catch (e) {}; + // sometimes require returns empty object (this bug is present in requirejs 2 as well) + if (module && module.Mode) + return done(module); + + // set mode to text until loading is finished + if (!this.$mode) + this.$setModePlaceholder(); + + fetch(mode, function() { + require([mode], done); + }); + + function done(module) { + if (_self.$modes[mode]) + return callback(_self.$modes[mode]); + + _self.$modes[mode] = new module.Mode(); + _self.$modes[mode].$id = mode; + _self._emit("loadmode", { + name: mode, + mode: _self.$modes[mode] + }); + callback(_self.$modes[mode]); + } + + function fetch(name, callback) { + if (!config.get("packaged")) + return callback(); + + net.loadScript(config.moduleUrl(name, "mode"), callback); + } + }; + + this.$setModePlaceholder = function() { + this.$mode = this.$modes["null"]; + var tokenizer = this.$mode.getTokenizer(); + + if (!this.bgTokenizer) { + this.bgTokenizer = new BackgroundTokenizer(tokenizer); + var _self = this; + this.bgTokenizer.addEventListener("update", function(e) { + _self._emit("tokenizerUpdate", e); + }); + } else { + this.bgTokenizer.setTokenizer(tokenizer); + } + this.bgTokenizer.setDocument(this.getDocument()); + + this.tokenRe = this.$mode.tokenRe; + this.nonTokenRe = this.$mode.nonTokenRe; + }; + + /** + * EditSession.setMode(mode) + * - mode (TextMode): Set a new text mode + * + * Sets a new text mode for the `EditSession`. This method also emits the `'changeMode'` event. If a [[BackgroundTokenizer `BackgroundTokenizer`]] is set, the `'tokenizerUpdate'` event is also emitted. + * + **/ + this.$mode = null; + this.$modeId = null; + this.setMode = function(mode) { + mode = mode || "null"; + // load on demand + if (typeof mode === "string") { + if (this.$modeId == mode) + return; + + this.$modeId = mode; + var _self = this; + this._loadMode(mode, function(module) { + if (_self.$modeId !== mode) + return; + + _self.setMode(module); + }); + return; + } + + if (this.$mode === mode) return; + this.$mode = mode; + this.$modeId = mode.$id; + + this.$stopWorker(); + + if (this.$useWorker) + this.$startWorker(); + + var tokenizer = mode.getTokenizer(); + + if(tokenizer.addEventListener !== undefined) { + var onReloadTokenizer = this.onReloadTokenizer.bind(this); + tokenizer.addEventListener("update", onReloadTokenizer); + } + + if (!this.bgTokenizer) { + this.bgTokenizer = new BackgroundTokenizer(tokenizer); + var _self = this; + this.bgTokenizer.addEventListener("update", function(e) { + _self._emit("tokenizerUpdate", e); + }); + } else { + this.bgTokenizer.setTokenizer(tokenizer); + } + + this.bgTokenizer.setDocument(this.getDocument()); + this.bgTokenizer.start(0); + + this.tokenRe = mode.tokenRe; + this.nonTokenRe = mode.nonTokenRe; + + this.$setFolding(mode.foldingRules); + + this._emit("changeMode"); + }; + + /** internal, hide + * EditSession.stopWorker() + * + * + **/ + this.$stopWorker = function() { + if (this.$worker) + this.$worker.terminate(); + + this.$worker = null; + }; + + /** internal, hide + * EditSession.$startWorker() + * + * + **/ + this.$startWorker = function() { + if (typeof Worker !== "undefined" && !require.noWorker) { + try { + this.$worker = this.$mode.createWorker(this); + } catch (e) { + console.log("Could not load worker"); + console.log(e); + this.$worker = null; + } + } + else + this.$worker = null; + }; + + /** + * EditSession.getMode() -> TextMode + * + * Returns the current text mode. + **/ + this.getMode = function() { + return this.$mode; + }; + + this.$scrollTop = 0; + /** + * EditSession.setScrollTop(scrollTop) + * - scrollTop (Number): The new scroll top value + * + * This function sets the scroll top value. It also emits the `'changeScrollTop'` event. + **/ + this.setScrollTop = function(scrollTop) { + scrollTop = Math.round(Math.max(0, scrollTop)); + if (this.$scrollTop === scrollTop) + return; + + this.$scrollTop = scrollTop; + this._emit("changeScrollTop", scrollTop); + }; + + /** + * EditSession.getScrollTop() -> Number + * + * [Returns the value of the distance between the top of the editor and the topmost part of the visible content.]{: #EditSession.getScrollTop} + **/ + this.getScrollTop = function() { + return this.$scrollTop; + }; + + this.$scrollLeft = 0; + /** + * EditSession.setScrollLeft(scrollLeft) + * + * [Sets the value of the distance between the left of the editor and the leftmost part of the visible content.]{: #EditSession.setScrollLeft} + **/ + this.setScrollLeft = function(scrollLeft) { + scrollLeft = Math.round(Math.max(0, scrollLeft)); + if (this.$scrollLeft === scrollLeft) + return; + + this.$scrollLeft = scrollLeft; + this._emit("changeScrollLeft", scrollLeft); + }; + + /** + * EditSession.getScrollLeft() -> Number + * + * [Returns the value of the distance between the left of the editor and the leftmost part of the visible content.]{: #EditSession.getScrollLeft} + **/ + this.getScrollLeft = function() { + return this.$scrollLeft; + }; + + /** + * EditSession.getScreenWidth() -> Number + * + * Returns the width of the screen. + **/ + this.getScreenWidth = function() { + this.$computeWidth(); + return this.screenWidth; + }; + + this.$computeWidth = function(force) { + if (this.$modified || force) { + this.$modified = false; + + if (this.$useWrapMode) + return this.screenWidth = this.$wrapLimit; + + var lines = this.doc.getAllLines(); + var cache = this.$rowLengthCache; + var longestScreenLine = 0; + var foldIndex = 0; + var foldLine = this.$foldData[foldIndex]; + var foldStart = foldLine ? foldLine.start.row : Infinity; + var len = lines.length; + + for (var i = 0; i < len; i++) { + if (i > foldStart) { + i = foldLine.end.row + 1; + if (i >= len) + break; + foldLine = this.$foldData[foldIndex++]; + foldStart = foldLine ? foldLine.start.row : Infinity; + } + + if (cache[i] == null) + cache[i] = this.$getStringScreenWidth(lines[i])[0]; + + if (cache[i] > longestScreenLine) + longestScreenLine = cache[i]; + } + this.screenWidth = longestScreenLine; + } + }; + + /** related to: Document.getLine + * EditSession.getLine(row) -> String + * - row (Number): The row to retrieve from + * + * Returns a verbatim copy of the given line as it is in the document + * + **/ + this.getLine = function(row) { + return this.doc.getLine(row); + }; + + /** related to: Document.getLines + * EditSession.getLines(firstRow, lastRow) -> Array + * - firstRow (Number): The first row index to retrieve + * - lastRow (Number): The final row index to retrieve + * + * Returns an array of strings of the rows between `firstRow` and `lastRow`. This function is inclusive of `lastRow`. + * + **/ + this.getLines = function(firstRow, lastRow) { + return this.doc.getLines(firstRow, lastRow); + }; + + /** related to: Document.getLength + * EditSession.getLength()-> Number + * + * Returns the number of rows in the document. + **/ + this.getLength = function() { + return this.doc.getLength(); + }; + + /** related to: Document.getTextRange + * EditSession.getTextRange(range) -> String + * - range (Range): The range to work with + * + * {:Document.getTextRange.desc} + **/ + this.getTextRange = function(range) { + return this.doc.getTextRange(range || this.selection.getRange()); + }; + + /** related to: Document.insert + * EditSession.insert(position, text) -> Number + * - position (Number): The position to start inserting at + * - text (String): A chunk of text to insert + * + (Number): The position of the last line of `text`. If the length of `text` is 0, this function simply returns `position`. + * + * Inserts a block of `text` and the indicated `position`. + * + * + **/ + this.insert = function(position, text) { + return this.doc.insert(position, text); + }; + + /** related to: Document.remove + * EditSession.remove(range) -> Object + * - range (Range): A specified Range to remove + * + (Object): The new `start` property of the range, which contains `startRow` and `startColumn`. If `range` is empty, this function returns the unmodified value of `range.start`. + * + * Removes the `range` from the document. + * + * + **/ + this.remove = function(range) { + return this.doc.remove(range); + }; + + /** + * EditSession.undoChanges(deltas, dontSelect) -> Range + * - deltas (Array): An array of previous changes + * - dontSelect (Boolean): [If `true`, doesn't select the range of where the change occured]{: #dontSelect} + * + * Reverts previous changes to your document. + **/ + this.undoChanges = function(deltas, dontSelect) { + if (!deltas.length) + return; + + this.$fromUndo = true; + var lastUndoRange = null; + for (var i = deltas.length - 1; i != -1; i--) { + var delta = deltas[i]; + if (delta.group == "doc") { + this.doc.revertDeltas(delta.deltas); + lastUndoRange = + this.$getUndoSelection(delta.deltas, true, lastUndoRange); + } else { + delta.deltas.forEach(function(foldDelta) { + this.addFolds(foldDelta.folds); + }, this); + } + } + this.$fromUndo = false; + lastUndoRange && + this.$undoSelect && + !dontSelect && + this.selection.setSelectionRange(lastUndoRange); + return lastUndoRange; + }; + + /** + * EditSession.redoChanges(deltas, dontSelect) -> Range + * - deltas (Array): An array of previous changes + * - dontSelect (Boolean): {:dontSelect} + * + * Re-implements a previously undone change to your document. + **/ + this.redoChanges = function(deltas, dontSelect) { + if (!deltas.length) + return; + + this.$fromUndo = true; + var lastUndoRange = null; + for (var i = 0; i < deltas.length; i++) { + var delta = deltas[i]; + if (delta.group == "doc") { + this.doc.applyDeltas(delta.deltas); + lastUndoRange = + this.$getUndoSelection(delta.deltas, false, lastUndoRange); + } + } + this.$fromUndo = false; + lastUndoRange && + this.$undoSelect && + !dontSelect && + this.selection.setSelectionRange(lastUndoRange); + return lastUndoRange; + }; + + /** + * EditSession.setUndoSelect(enable) + * - enable (Boolean): If `true`, selects the range of the reinserted change + * + * ENables or disables highlighting of the range where an undo occured. + **/ + this.setUndoSelect = function(enable) { + this.$undoSelect = enable; + }; + + /** internal, hide + * EditSession.$getUndoSelection(deltas, isUndo, lastUndoRange) -> Range + * + * + **/ + this.$getUndoSelection = function(deltas, isUndo, lastUndoRange) { + function isInsert(delta) { + var insert = + delta.action == "insertText" || delta.action == "insertLines"; + return isUndo ? !insert : insert; + } + + var delta = deltas[0]; + var range, point; + var lastDeltaIsInsert = false; + if (isInsert(delta)) { + range = delta.range.clone(); + lastDeltaIsInsert = true; + } else { + range = Range.fromPoints(delta.range.start, delta.range.start); + lastDeltaIsInsert = false; + } + + for (var i = 1; i < deltas.length; i++) { + delta = deltas[i]; + if (isInsert(delta)) { + point = delta.range.start; + if (range.compare(point.row, point.column) == -1) { + range.setStart(delta.range.start); + } + point = delta.range.end; + if (range.compare(point.row, point.column) == 1) { + range.setEnd(delta.range.end); + } + lastDeltaIsInsert = true; + } else { + point = delta.range.start; + if (range.compare(point.row, point.column) == -1) { + range = + Range.fromPoints(delta.range.start, delta.range.start); + } + lastDeltaIsInsert = false; + } + } + + // Check if this range and the last undo range has something in common. + // If true, merge the ranges. + if (lastUndoRange != null) { + var cmp = lastUndoRange.compareRange(range); + if (cmp == 1) { + range.setStart(lastUndoRange.start); + } else if (cmp == -1) { + range.setEnd(lastUndoRange.end); + } + } + + return range; + }, + + /** related to: Document.replace + * EditSession.replace(range, text) -> Object + * - range (Range): A specified Range to replace + * - text (String): The new text to use as a replacement + * + (Object): Returns an object containing the final row and column, like this:
+ * ```{row: endRow, column: 0}```
+ * If the text and range are empty, this function returns an object containing the current `range.start` value.
+ * If the text is the exact same as what currently exists, this function returns an object containing the current `range.end` value. + * + * Replaces a range in the document with the new `text`. + * + * + * + **/ + this.replace = function(range, text) { + return this.doc.replace(range, text); + }; + + /** + * EditSession.moveText(fromRange, toPosition) -> Range + * - fromRange (Range): The range of text you want moved within the document + * - toPosition (Object): The location (row and column) where you want to move the text to + * + (Range): The new range where the text was moved to. + * Moves a range of text from the given range to the given position. `toPosition` is an object that looks like this: + * + * { row: newRowLocation, column: newColumnLocation } + * + * + * + **/ + this.moveText = function(fromRange, toPosition) { + var text = this.getTextRange(fromRange); + this.remove(fromRange); + + var toRow = toPosition.row; + var toColumn = toPosition.column; + + // Make sure to update the insert location, when text is removed in + // front of the chosen point of insertion. + if (!fromRange.isMultiLine() && fromRange.start.row == toRow && + fromRange.end.column < toColumn) + toColumn -= text.length; + + if (fromRange.isMultiLine() && fromRange.end.row < toRow) { + var lines = this.doc.$split(text); + toRow -= lines.length - 1; + } + + var endRow = toRow + fromRange.end.row - fromRange.start.row; + var endColumn = fromRange.isMultiLine() ? + fromRange.end.column : + toColumn + fromRange.end.column - fromRange.start.column; + + var toRange = new Range(toRow, toColumn, endRow, endColumn); + + this.insert(toRange.start, text); + + return toRange; + }; + + /** + * EditSession.indentRows(startRow, endRow, indentString) + * - startRow (Number): Starting row + * - endRow (Number): Ending row + * - indentString (String): The indent token + * + * Indents all the rows, from `startRow` to `endRow` (inclusive), by prefixing each row with the token in `indentString`. + * + * If `indentString` contains the `'\t'` character, it's replaced by whatever is defined by [[EditSession.getTabString `getTabString()`]]. + * + **/ + this.indentRows = function(startRow, endRow, indentString) { + indentString = indentString.replace(/\t/g, this.getTabString()); + for (var row=startRow; row<=endRow; row++) + this.insert({row: row, column:0}, indentString); + }; + + /** + * EditSession.outdentRows(range) + * - range (Range): A range of rows + * + * Outdents all the rows defined by the `start` and `end` properties of `range`. + * + **/ + this.outdentRows = function (range) { + var rowRange = range.collapseRows(); + var deleteRange = new Range(0, 0, 0, 0); + var size = this.getTabSize(); + + for (var i = rowRange.start.row; i <= rowRange.end.row; ++i) { + var line = this.getLine(i); + + deleteRange.start.row = i; + deleteRange.end.row = i; + for (var j = 0; j < size; ++j) + if (line.charAt(j) != ' ') + break; + if (j < size && line.charAt(j) == '\t') { + deleteRange.start.column = j; + deleteRange.end.column = j + 1; + } else { + deleteRange.start.column = 0; + deleteRange.end.column = j; + } + this.remove(deleteRange); + } + }; + + /** related to: Document.insertLines + * EditSession.moveLinesUp(firstRow, lastRow) -> Number + * - firstRow (Number): The starting row to move up + * - lastRow (Number): The final row to move up + * + (Number): If `firstRow` is less-than or equal to 0, this function returns 0. Otherwise, on success, it returns -1. + * + * Shifts all the lines in the document up one, starting from `firstRow` and ending at `lastRow`. + * + * + **/ + this.moveLinesUp = function(firstRow, lastRow) { + if (firstRow <= 0) return 0; + + var removed = this.doc.removeLines(firstRow, lastRow); + this.doc.insertLines(firstRow - 1, removed); + return -1; + }; + + /** related to: Document.insertLines + * EditSession.moveLinesDown(firstRow, lastRow) -> Number + * - firstRow (Number): The starting row to move down + * - lastRow (Number): The final row to move down + * + (Number): If `firstRow` is less-than or equal to 0, this function returns 0. Otherwise, on success, it returns -1. + * + * + * + **/ + this.moveLinesDown = function(firstRow, lastRow) { + if (lastRow >= this.doc.getLength()-1) return 0; + + var removed = this.doc.removeLines(firstRow, lastRow); + this.doc.insertLines(firstRow+1, removed); + return 1; + }; + + /** + * EditSession.duplicateLines(firstRow, lastRow) -> Number + * - firstRow (Number): The starting row to duplicate + * - lastRow (Number): The final row to duplicate + * + (Number): Returns the number of new rows added; in other words, `lastRow - firstRow + 1`. + * + * Duplicates all the text between `firstRow` and `lastRow`. + * + * + * + **/ + this.duplicateLines = function(firstRow, lastRow) { + var firstRow = this.$clipRowToDocument(firstRow); + var lastRow = this.$clipRowToDocument(lastRow); + + var lines = this.getLines(firstRow, lastRow); + this.doc.insertLines(firstRow, lines); + + var addedRows = lastRow - firstRow + 1; + return addedRows; + }; + + + this.$clipRowToDocument = function(row) { + return Math.max(0, Math.min(row, this.doc.getLength()-1)); + }; + + this.$clipColumnToRow = function(row, column) { + if (column < 0) + return 0; + return Math.min(this.doc.getLine(row).length, column); + }; + + + this.$clipPositionToDocument = function(row, column) { + column = Math.max(0, column); + + if (row < 0) { + row = 0; + column = 0; + } else { + var len = this.doc.getLength(); + if (row >= len) { + row = len - 1; + column = this.doc.getLine(len-1).length; + } else { + column = Math.min(this.doc.getLine(row).length, column); + } + } + + return { + row: row, + column: column + }; + }; + + this.$clipRangeToDocument = function(range) { + if (range.start.row < 0) { + range.start.row = 0; + range.start.column = 0; + } else { + range.start.column = this.$clipColumnToRow( + range.start.row, + range.start.column + ); + } + + var len = this.doc.getLength() - 1; + if (range.end.row > len) { + range.end.row = len; + range.end.column = this.doc.getLine(len).length; + } else { + range.end.column = this.$clipColumnToRow( + range.end.row, + range.end.column + ); + } + return range; + }; + + // WRAPMODE + this.$wrapLimit = 80; + this.$useWrapMode = false; + this.$wrapLimitRange = { + min : null, + max : null + }; + + /** + * EditSession.setUseWrapMode(useWrapMode) + * - useWrapMode (Boolean): Enable (or disable) wrap mode + * + * Sets whether or not line wrapping is enabled. If `useWrapMode` is different than the current value, the `'changeWrapMode'` event is emitted. + **/ + this.setUseWrapMode = function(useWrapMode) { + if (useWrapMode != this.$useWrapMode) { + this.$useWrapMode = useWrapMode; + this.$modified = true; + this.$resetRowCache(0); + + // If wrapMode is activaed, the wrapData array has to be initialized. + if (useWrapMode) { + var len = this.getLength(); + this.$wrapData = []; + for (var i = 0; i < len; i++) { + this.$wrapData.push([]); + } + this.$updateWrapData(0, len - 1); + } + + this._emit("changeWrapMode"); + } + }; + + /** + * EditSession.getUseWrapMode() -> Boolean + * + * Returns `true` if wrap mode is being used; `false` otherwise. + **/ + this.getUseWrapMode = function() { + return this.$useWrapMode; + }; + + // Allow the wrap limit to move freely between min and max. Either + // parameter can be null to allow the wrap limit to be unconstrained + // in that direction. Or set both parameters to the same number to pin + // the limit to that value. + /** + * EditSession.setWrapLimitRange(min, max) + * - min (Number): The minimum wrap value (the left side wrap) + * - max (Number): The maximum wrap value (the right side wrap) + * + * Sets the boundaries of wrap. Either value can be `null` to have an unconstrained wrap, or, they can be the same number to pin the limit. If the wrap limits for `min` or `max` are different, this method also emits the `'changeWrapMode'` event. + **/ + this.setWrapLimitRange = function(min, max) { + if (this.$wrapLimitRange.min !== min || this.$wrapLimitRange.max !== max) { + this.$wrapLimitRange.min = min; + this.$wrapLimitRange.max = max; + this.$modified = true; + // This will force a recalculation of the wrap limit + this._emit("changeWrapMode"); + } + }; + + /** internal, hide + * EditSession.adjustWrapLimit(desiredLimit) -> Boolean + * - desiredLimit (Number): The new wrap limit + * + * This should generally only be called by the renderer when a resize is detected. + **/ + this.adjustWrapLimit = function(desiredLimit) { + var wrapLimit = this.$constrainWrapLimit(desiredLimit); + if (wrapLimit != this.$wrapLimit && wrapLimit > 0) { + this.$wrapLimit = wrapLimit; + this.$modified = true; + if (this.$useWrapMode) { + this.$updateWrapData(0, this.getLength() - 1); + this.$resetRowCache(0); + this._emit("changeWrapLimit"); + } + return true; + } + return false; + }; + + /** internal, hide + * EditSession.$constrainWrapLimit(wrapLimit) + * + * + **/ + this.$constrainWrapLimit = function(wrapLimit) { + var min = this.$wrapLimitRange.min; + if (min) + wrapLimit = Math.max(min, wrapLimit); + + var max = this.$wrapLimitRange.max; + if (max) + wrapLimit = Math.min(max, wrapLimit); + + // What would a limit of 0 even mean? + return Math.max(1, wrapLimit); + }; + + /** + * EditSession.getWrapLimit() -> Number + * + * Returns the value of wrap limit. + **/ + this.getWrapLimit = function() { + return this.$wrapLimit; + }; + + /** + * EditSession.getWrapLimitRange() -> Object + * + * Returns an object that defines the minimum and maximum of the wrap limit; it looks something like this: + * + * { min: wrapLimitRange_min, max: wrapLimitRange_max } + * + **/ + this.getWrapLimitRange = function() { + // Avoid unexpected mutation by returning a copy + return { + min : this.$wrapLimitRange.min, + max : this.$wrapLimitRange.max + }; + }; + + /** internal, hide + * EditSession.$updateInternalDataOnChange() + * + * + **/ + this.$updateInternalDataOnChange = function(e) { + var useWrapMode = this.$useWrapMode; + var len; + var action = e.data.action; + var firstRow = e.data.range.start.row; + var lastRow = e.data.range.end.row; + var start = e.data.range.start; + var end = e.data.range.end; + var removedFolds = null; + + if (action.indexOf("Lines") != -1) { + if (action == "insertLines") { + lastRow = firstRow + (e.data.lines.length); + } else { + lastRow = firstRow; + } + len = e.data.lines ? e.data.lines.length : lastRow - firstRow; + } else { + len = lastRow - firstRow; + } + + if (len != 0) { + if (action.indexOf("remove") != -1) { + this[useWrapMode ? "$wrapData" : "$rowLengthCache"].splice(firstRow, len); + + var foldLines = this.$foldData; + removedFolds = this.getFoldsInRange(e.data.range); + this.removeFolds(removedFolds); + + var foldLine = this.getFoldLine(end.row); + var idx = 0; + if (foldLine) { + foldLine.addRemoveChars(end.row, end.column, start.column - end.column); + foldLine.shiftRow(-len); + + var foldLineBefore = this.getFoldLine(firstRow); + if (foldLineBefore && foldLineBefore !== foldLine) { + foldLineBefore.merge(foldLine); + foldLine = foldLineBefore; + } + idx = foldLines.indexOf(foldLine) + 1; + } + + for (idx; idx < foldLines.length; idx++) { + var foldLine = foldLines[idx]; + if (foldLine.start.row >= end.row) { + foldLine.shiftRow(-len); + } + } + + lastRow = firstRow; + } else { + var args; + if (useWrapMode) { + args = [firstRow, 0]; + for (var i = 0; i < len; i++) args.push([]); + this.$wrapData.splice.apply(this.$wrapData, args); + } else { + args = Array(len); + args.unshift(firstRow, 0); + this.$rowLengthCache.splice.apply(this.$rowLengthCache, args); + } + + // If some new line is added inside of a foldLine, then split + // the fold line up. + var foldLines = this.$foldData; + var foldLine = this.getFoldLine(firstRow); + var idx = 0; + if (foldLine) { + var cmp = foldLine.range.compareInside(start.row, start.column) + // Inside of the foldLine range. Need to split stuff up. + if (cmp == 0) { + foldLine = foldLine.split(start.row, start.column); + foldLine.shiftRow(len); + foldLine.addRemoveChars( + lastRow, 0, end.column - start.column); + } else + // Infront of the foldLine but same row. Need to shift column. + if (cmp == -1) { + foldLine.addRemoveChars(firstRow, 0, end.column - start.column); + foldLine.shiftRow(len); + } + // Nothing to do if the insert is after the foldLine. + idx = foldLines.indexOf(foldLine) + 1; + } + + for (idx; idx < foldLines.length; idx++) { + var foldLine = foldLines[idx]; + if (foldLine.start.row >= firstRow) { + foldLine.shiftRow(len); + } + } + } + } else { + // Realign folds. E.g. if you add some new chars before a fold, the + // fold should "move" to the right. + len = Math.abs(e.data.range.start.column - e.data.range.end.column); + if (action.indexOf("remove") != -1) { + // Get all the folds in the change range and remove them. + removedFolds = this.getFoldsInRange(e.data.range); + this.removeFolds(removedFolds); + + len = -len; + } + var foldLine = this.getFoldLine(firstRow); + if (foldLine) { + foldLine.addRemoveChars(firstRow, start.column, len); + } + } + + if (useWrapMode && this.$wrapData.length != this.doc.getLength()) { + console.error("doc.getLength() and $wrapData.length have to be the same!"); + } + + if (useWrapMode) + this.$updateWrapData(firstRow, lastRow); + else + this.$updateRowLengthCache(firstRow, lastRow); + + return removedFolds; + }; + + this.$updateRowLengthCache = function(firstRow, lastRow, b) { + this.$rowLengthCache[firstRow] = null; + this.$rowLengthCache[lastRow] = null; + }; + + /** internal, hide + * EditSession.$updateWrapData(firstRow, lastRow) + * + **/ + this.$updateWrapData = function(firstRow, lastRow) { + var lines = this.doc.getAllLines(); + var tabSize = this.getTabSize(); + var wrapData = this.$wrapData; + var wrapLimit = this.$wrapLimit; + var tokens; + var foldLine; + + var row = firstRow; + lastRow = Math.min(lastRow, lines.length - 1); + while (row <= lastRow) { + foldLine = this.getFoldLine(row, foldLine); + if (!foldLine) { + tokens = this.$getDisplayTokens(lang.stringTrimRight(lines[row])); + wrapData[row] = this.$computeWrapSplits(tokens, wrapLimit, tabSize); + row ++; + } else { + tokens = []; + foldLine.walk(function(placeholder, row, column, lastColumn) { + var walkTokens; + if (placeholder != null) { + walkTokens = this.$getDisplayTokens( + placeholder, tokens.length); + walkTokens[0] = PLACEHOLDER_START; + for (var i = 1; i < walkTokens.length; i++) { + walkTokens[i] = PLACEHOLDER_BODY; + } + } else { + walkTokens = this.$getDisplayTokens( + lines[row].substring(lastColumn, column), + tokens.length); + } + tokens = tokens.concat(walkTokens); + }.bind(this), + foldLine.end.row, + lines[foldLine.end.row].length + 1 + ); + // Remove spaces/tabs from the back of the token array. + while (tokens.length != 0 && tokens[tokens.length - 1] >= SPACE) + tokens.pop(); + + wrapData[foldLine.start.row] + = this.$computeWrapSplits(tokens, wrapLimit, tabSize); + row = foldLine.end.row + 1; + } + } + }; + + // "Tokens" + var CHAR = 1, + CHAR_EXT = 2, + PLACEHOLDER_START = 3, + PLACEHOLDER_BODY = 4, + PUNCTUATION = 9, + SPACE = 10, + TAB = 11, + TAB_SPACE = 12; + + /** internal, hide + * EditSession.$computeWrapSplits(tokens, wrapLimit) -> Array + * + * + **/ + this.$computeWrapSplits = function(tokens, wrapLimit) { + if (tokens.length == 0) { + return []; + } + + var splits = []; + var displayLength = tokens.length; + var lastSplit = 0, lastDocSplit = 0; + + function addSplit(screenPos) { + var displayed = tokens.slice(lastSplit, screenPos); + + // The document size is the current size - the extra width for tabs + // and multipleWidth characters. + var len = displayed.length; + displayed.join(""). + // Get all the TAB_SPACEs. + replace(/12/g, function() { + len -= 1; + }). + // Get all the CHAR_EXT/multipleWidth characters. + replace(/2/g, function() { + len -= 1; + }); + + lastDocSplit += len; + splits.push(lastDocSplit); + lastSplit = screenPos; + } + + while (displayLength - lastSplit > wrapLimit) { + // This is, where the split should be. + var split = lastSplit + wrapLimit; + + // If there is a space or tab at this split position, then making + // a split is simple. + if (tokens[split] >= SPACE) { + // Include all following spaces + tabs in this split as well. + while (tokens[split] >= SPACE) { + split ++; + } + addSplit(split); + continue; + } + + // === ELSE === + // Check if split is inside of a placeholder. Placeholder are + // not splitable. Therefore, seek the beginning of the placeholder + // and try to place the split beofre the placeholder's start. + if (tokens[split] == PLACEHOLDER_START + || tokens[split] == PLACEHOLDER_BODY) + { + // Seek the start of the placeholder and do the split + // before the placeholder. By definition there always + // a PLACEHOLDER_START between split and lastSplit. + for (split; split != lastSplit - 1; split--) { + if (tokens[split] == PLACEHOLDER_START) { + // split++; << No incremental here as we want to + // have the position before the Placeholder. + break; + } + } + + // If the PLACEHOLDER_START is not the index of the + // last split, then we can do the split + if (split > lastSplit) { + addSplit(split); + continue; + } + + // If the PLACEHOLDER_START IS the index of the last + // split, then we have to place the split after the + // placeholder. So, let's seek for the end of the placeholder. + split = lastSplit + wrapLimit; + for (split; split < tokens.length; split++) { + if (tokens[split] != PLACEHOLDER_BODY) + { + break; + } + } + + // If spilt == tokens.length, then the placeholder is the last + // thing in the line and adding a new split doesn't make sense. + if (split == tokens.length) { + break; // Breaks the while-loop. + } + + // Finally, add the split... + addSplit(split); + continue; + } + + // === ELSE === + // Search for the first non space/tab/placeholder/punctuation token backwards. + var minSplit = Math.max(split - 10, lastSplit - 1); + while (split > minSplit && tokens[split] < PLACEHOLDER_START) { + split --; + } + while (split > minSplit && tokens[split] == PUNCTUATION) { + split --; + } + // If we found one, then add the split. + if (split > minSplit) { + addSplit(++split); + continue; + } + + // === ELSE === + split = lastSplit + wrapLimit; + // The split is inside of a CHAR or CHAR_EXT token and no space + // around -> force a split. + addSplit(split); + } + return splits; + }; + + /** internal, hide + * EditSession.$getDisplayTokens(str, offset) -> Array + * - str (String): The string to check + * - offset (Number): The value to start at + * + * Given a string, returns an array of the display characters, including tabs and spaces. + **/ + this.$getDisplayTokens = function(str, offset) { + var arr = []; + var tabSize; + offset = offset || 0; + + for (var i = 0; i < str.length; i++) { + var c = str.charCodeAt(i); + // Tab + if (c == 9) { + tabSize = this.getScreenTabSize(arr.length + offset); + arr.push(TAB); + for (var n = 1; n < tabSize; n++) { + arr.push(TAB_SPACE); + } + } + // Space + else if (c == 32) { + arr.push(SPACE); + } else if((c > 39 && c < 48) || (c > 57 && c < 64)) { + arr.push(PUNCTUATION); + } + // full width characters + else if (c >= 0x1100 && isFullWidth(c)) { + arr.push(CHAR, CHAR_EXT); + } else { + arr.push(CHAR); + } + } + return arr; + }; + + /** internal, hide + * EditSession.$getStringScreenWidth(str, maxScreenColumn, screenColumn) -> [Number] + * - str (String): The string to calculate the screen width of + * - maxScreenColumn (Number): + * - screenColumn (Number): + * + ([Number]): Returns an `int[]` array with two elements:
+ * The first position indicates the number of columns for `str` on screen.
+ * The second value contains the position of the document column that this function read until. + * + * Calculates the width of the string `str` on the screen while assuming that the string starts at the first column on the screen. + * + * + **/ + this.$getStringScreenWidth = function(str, maxScreenColumn, screenColumn) { + if (maxScreenColumn == 0) + return [0, 0]; + if (maxScreenColumn == null) + maxScreenColumn = Infinity; + screenColumn = screenColumn || 0; + + var c, column; + for (column = 0; column < str.length; column++) { + c = str.charCodeAt(column); + // tab + if (c == 9) { + screenColumn += this.getScreenTabSize(screenColumn); + } + // full width characters + else if (c >= 0x1100 && isFullWidth(c)) { + screenColumn += 2; + } else { + screenColumn += 1; + } + if (screenColumn > maxScreenColumn) { + break; + } + } + + return [screenColumn, column]; + }; + + /** + * EditSession.getRowLength(row) -> Number + * - row (Number): The row number to check + * + * + * Returns number of screenrows in a wrapped line. + **/ + this.getRowLength = function(row) { + if (!this.$useWrapMode || !this.$wrapData[row]) { + return 1; + } else { + return this.$wrapData[row].length + 1; + } + }; + + /** internal, hide, related to: EditSession.documentToScreenColumn + * EditSession.getScreenLastRowColumn(screenRow) -> Number + * - screenRow (Number): The screen row to check + * + * Returns the column position (on screen) for the last character in the provided row. + **/ + this.getScreenLastRowColumn = function(screenRow) { + var pos = this.screenToDocumentPosition(screenRow, Number.MAX_VALUE); + return this.documentToScreenColumn(pos.row, pos.column); + }; + + /** internal, hide + * EditSession.getDocumentLastRowColumn(docRow, docColumn) -> Number + * - docRow (Number): + * - docColumn (Number): + * + **/ + this.getDocumentLastRowColumn = function(docRow, docColumn) { + var screenRow = this.documentToScreenRow(docRow, docColumn); + return this.getScreenLastRowColumn(screenRow); + }; + + /** internal, hide + * EditSession.getDocumentLastRowColumnPosition(docRow, docColumn) -> Number + * + **/ + this.getDocumentLastRowColumnPosition = function(docRow, docColumn) { + var screenRow = this.documentToScreenRow(docRow, docColumn); + return this.screenToDocumentPosition(screenRow, Number.MAX_VALUE / 10); + }; + + /** internal, hide + * EditSession.getRowSplitData(row) -> undefined | String + * + **/ + this.getRowSplitData = function(row) { + if (!this.$useWrapMode) { + return undefined; + } else { + return this.$wrapData[row]; + } + }; + + /** + * EditSession.getScreenTabSize(screenColumn) -> Number + * - screenColumn (Number): The screen column to check + * + * The distance to the next tab stop at the specified screen column. + **/ + this.getScreenTabSize = function(screenColumn) { + return this.$tabSize - screenColumn % this.$tabSize; + }; + + /** internal, hide + * EditSession.screenToDocumentRow(screenRow, screenColumn) -> Number + * + * + **/ + this.screenToDocumentRow = function(screenRow, screenColumn) { + return this.screenToDocumentPosition(screenRow, screenColumn).row; + }; + + /** internal, hide + * EditSession.screenToDocumentColumn(screenRow, screenColumn) -> Number + * + * + **/ + this.screenToDocumentColumn = function(screenRow, screenColumn) { + return this.screenToDocumentPosition(screenRow, screenColumn).column; + }; + + /** related to: EditSession.documentToScreenPosition + * EditSession.screenToDocumentPosition(screenRow, screenColumn) -> Object + * - screenRow (Number): The screen row to check + * - screenColumn (Number): The screen column to check + * + (Object): The object returned has two properties: `row` and `column`. + * + * Converts characters coordinates on the screen to characters coordinates within the document. [This takes into account code folding, word wrap, tab size, and any other visual modifications.]{: #conversionConsiderations} + * + * + **/ + this.screenToDocumentPosition = function(screenRow, screenColumn) { + if (screenRow < 0) + return {row: 0, column: 0}; + + var line; + var docRow = 0; + var docColumn = 0; + var column; + var row = 0; + var rowLength = 0; + + var rowCache = this.$screenRowCache; + var i = this.$getRowCacheIndex(rowCache, screenRow); + if (0 < i && i < rowCache.length) { + var row = rowCache[i]; + var docRow = this.$docRowCache[i]; + var doCache = screenRow > row || (screenRow == row && i == rowCache.length - 1); + } else { + var doCache = i != 0 || !rowCache.length; + } + + var maxRow = this.getLength() - 1; + var foldLine = this.getNextFoldLine(docRow); + var foldStart = foldLine ? foldLine.start.row : Infinity; + + while (row <= screenRow) { + rowLength = this.getRowLength(docRow); + if (row + rowLength - 1 >= screenRow || docRow >= maxRow) { + break; + } else { + row += rowLength; + docRow++; + if (docRow > foldStart) { + docRow = foldLine.end.row+1; + foldLine = this.getNextFoldLine(docRow, foldLine); + foldStart = foldLine ? foldLine.start.row : Infinity; + } + } + if (doCache) { + this.$docRowCache.push(docRow); + this.$screenRowCache.push(row); + } + } + + if (foldLine && foldLine.start.row <= docRow) { + line = this.getFoldDisplayLine(foldLine); + docRow = foldLine.start.row; + } else if (row + rowLength <= screenRow || docRow > maxRow) { + // clip at the end of the document + return { + row: maxRow, + column: this.getLine(maxRow).length + } + } else { + line = this.getLine(docRow); + foldLine = null; + } + + if (this.$useWrapMode) { + var splits = this.$wrapData[docRow]; + if (splits) { + column = splits[screenRow - row]; + if(screenRow > row && splits.length) { + docColumn = splits[screenRow - row - 1] || splits[splits.length - 1]; + line = line.substring(docColumn); + } + } + } + + docColumn += this.$getStringScreenWidth(line, screenColumn)[1]; + + // We remove one character at the end so that the docColumn + // position returned is not associated to the next row on the screen. + if (this.$useWrapMode && docColumn >= column) + docColumn = column - 1; + + if (foldLine) + return foldLine.idxToPosition(docColumn); + + return {row: docRow, column: docColumn}; + }; + + /** related to: EditSession.screenToDocumentPosition + * EditSession.documentToScreenPosition(docRow, docColumn) -> Object + * - docRow (Number): The document row to check + * - docColumn (Number): The document column to check + * + (Object): The object returned by this method has two properties: `row` and `column`. + * + * Converts document coordinates to screen coordinates. {:conversionConsiderations} + * + * + **/ + this.documentToScreenPosition = function(docRow, docColumn) { + // Normalize the passed in arguments. + if (typeof docColumn === "undefined") + var pos = this.$clipPositionToDocument(docRow.row, docRow.column); + else + pos = this.$clipPositionToDocument(docRow, docColumn); + + docRow = pos.row; + docColumn = pos.column; + + var screenRow = 0; + var foldStartRow = null; + var fold = null; + + // Clamp the docRow position in case it's inside of a folded block. + fold = this.getFoldAt(docRow, docColumn, 1); + if (fold) { + docRow = fold.start.row; + docColumn = fold.start.column; + } + + var rowEnd, row = 0; + + + var rowCache = this.$docRowCache; + var i = this.$getRowCacheIndex(rowCache, docRow); + if (0 < i && i < rowCache.length) { + var row = rowCache[i]; + var screenRow = this.$screenRowCache[i]; + var doCache = docRow > row || (docRow == row && i == rowCache.length - 1); + } else { + var doCache = i != 0 || !rowCache.length; + } + + var foldLine = this.getNextFoldLine(row); + var foldStart = foldLine ?foldLine.start.row :Infinity; + + while (row < docRow) { + if (row >= foldStart) { + rowEnd = foldLine.end.row + 1; + if (rowEnd > docRow) + break; + foldLine = this.getNextFoldLine(rowEnd, foldLine); + foldStart = foldLine ?foldLine.start.row :Infinity; + } + else { + rowEnd = row + 1; + } + + screenRow += this.getRowLength(row); + row = rowEnd; + + if (doCache) { + this.$docRowCache.push(row); + this.$screenRowCache.push(screenRow); + } + } + + // Calculate the text line that is displayed in docRow on the screen. + var textLine = ""; + // Check if the final row we want to reach is inside of a fold. + if (foldLine && row >= foldStart) { + textLine = this.getFoldDisplayLine(foldLine, docRow, docColumn); + foldStartRow = foldLine.start.row; + } else { + textLine = this.getLine(docRow).substring(0, docColumn); + foldStartRow = docRow; + } + // Clamp textLine if in wrapMode. + if (this.$useWrapMode) { + var wrapRow = this.$wrapData[foldStartRow]; + var screenRowOffset = 0; + while (textLine.length >= wrapRow[screenRowOffset]) { + screenRow ++; + screenRowOffset++; + } + textLine = textLine.substring( + wrapRow[screenRowOffset - 1] || 0, textLine.length + ); + } + + return { + row: screenRow, + column: this.$getStringScreenWidth(textLine)[0] + }; + }; + + /** internal, hide + * EditSession.documentToScreenColumn(row, docColumn) -> Number + * + * + **/ + this.documentToScreenColumn = function(row, docColumn) { + return this.documentToScreenPosition(row, docColumn).column; + }; + + /** internal, hide + * EditSession.documentToScreenRow(docRow, docColumn) -> Number + * + * + **/ + this.documentToScreenRow = function(docRow, docColumn) { + return this.documentToScreenPosition(docRow, docColumn).row; + }; + + /** + * EditSession.getScreenLength() -> Number + * + * Returns the length of the screen. + **/ + this.getScreenLength = function() { + var screenRows = 0; + var fold = null; + if (!this.$useWrapMode) { + screenRows = this.getLength(); + + // Remove the folded lines again. + var foldData = this.$foldData; + for (var i = 0; i < foldData.length; i++) { + fold = foldData[i]; + screenRows -= fold.end.row - fold.start.row; + } + } else { + var lastRow = this.$wrapData.length; + var row = 0, i = 0; + var fold = this.$foldData[i++]; + var foldStart = fold ? fold.start.row :Infinity; + + while (row < lastRow) { + screenRows += this.$wrapData[row].length + 1; + row ++; + if (row > foldStart) { + row = fold.end.row+1; + fold = this.$foldData[i++]; + foldStart = fold ?fold.start.row :Infinity; + } + } + } + + return screenRows; + } + + // For every keystroke this gets called once per char in the whole doc!! + // Wouldn't hurt to make it a bit faster for c >= 0x1100 + function isFullWidth(c) { + if (c < 0x1100) + return false; + return c >= 0x1100 && c <= 0x115F || + c >= 0x11A3 && c <= 0x11A7 || + c >= 0x11FA && c <= 0x11FF || + c >= 0x2329 && c <= 0x232A || + c >= 0x2E80 && c <= 0x2E99 || + c >= 0x2E9B && c <= 0x2EF3 || + c >= 0x2F00 && c <= 0x2FD5 || + c >= 0x2FF0 && c <= 0x2FFB || + c >= 0x3000 && c <= 0x303E || + c >= 0x3041 && c <= 0x3096 || + c >= 0x3099 && c <= 0x30FF || + c >= 0x3105 && c <= 0x312D || + c >= 0x3131 && c <= 0x318E || + c >= 0x3190 && c <= 0x31BA || + c >= 0x31C0 && c <= 0x31E3 || + c >= 0x31F0 && c <= 0x321E || + c >= 0x3220 && c <= 0x3247 || + c >= 0x3250 && c <= 0x32FE || + c >= 0x3300 && c <= 0x4DBF || + c >= 0x4E00 && c <= 0xA48C || + c >= 0xA490 && c <= 0xA4C6 || + c >= 0xA960 && c <= 0xA97C || + c >= 0xAC00 && c <= 0xD7A3 || + c >= 0xD7B0 && c <= 0xD7C6 || + c >= 0xD7CB && c <= 0xD7FB || + c >= 0xF900 && c <= 0xFAFF || + c >= 0xFE10 && c <= 0xFE19 || + c >= 0xFE30 && c <= 0xFE52 || + c >= 0xFE54 && c <= 0xFE66 || + c >= 0xFE68 && c <= 0xFE6B || + c >= 0xFF01 && c <= 0xFF60 || + c >= 0xFFE0 && c <= 0xFFE6; + }; + +}).call(EditSession.prototype); + +require("./edit_session/folding").Folding.call(EditSession.prototype); +require("./edit_session/bracket_match").BracketMatch.call(EditSession.prototype); + +exports.EditSession = EditSession; +}); diff --git a/lib/ace/edit_session/bracket_match.js b/lib/ace/edit_session/bracket_match.js new file mode 100644 index 0000000000..d3e1d76df5 --- /dev/null +++ b/lib/ace/edit_session/bracket_match.js @@ -0,0 +1,219 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var TokenIterator = require("../token_iterator").TokenIterator; +var Range = require("../range").Range; + + +function BracketMatch() { + + this.findMatchingBracket = function(position) { + if (position.column == 0) return null; + + var charBeforeCursor = this.getLine(position.row).charAt(position.column-1); + if (charBeforeCursor == "") return null; + + var match = charBeforeCursor.match(/([\(\[\{])|([\)\]\}])/); + if (!match) + return null; + + if (match[1]) + return this.$findClosingBracket(match[1], position); + else + return this.$findOpeningBracket(match[2], position); + }; + + this.getBracketRange = function(pos) { + var line = this.getLine(pos.row); + var before = true, range; + + var chr = line.charAt(pos.column-1); + var match = chr && chr.match(/([\(\[\{])|([\)\]\}])/); + if (!match) { + chr = line.charAt(pos.column); + pos = {row: pos.row, column: pos.column + 1}; + match = chr && chr.match(/([\(\[\{])|([\)\]\}])/); + before = false; + } + if (!match) + return null; + + if (match[1]) { + var bracketPos = this.$findClosingBracket(match[1], pos); + if (!bracketPos) + return null; + range = Range.fromPoints(pos, bracketPos); + if (!before) { + range.end.column++; + range.start.column--; + } + range.cursor = range.end; + } else { + var bracketPos = this.$findOpeningBracket(match[2], pos); + if (!bracketPos) + return null; + range = Range.fromPoints(bracketPos, pos); + if (!before) { + range.start.column++; + range.end.column--; + } + range.cursor = range.start; + } + + return range; + }; + + this.$brackets = { + ")": "(", + "(": ")", + "]": "[", + "[": "]", + "{": "}", + "}": "{" + }; + + this.$findOpeningBracket = function(bracket, position, typeRe) { + var openBracket = this.$brackets[bracket]; + var depth = 1; + + var iterator = new TokenIterator(this, position.row, position.column); + var token = iterator.getCurrentToken(); + if (!token) + token = iterator.stepForward(); + if (!token) + return; + + if (!typeRe){ + typeRe = new RegExp( + "(\\.?" + + token.type.replace(".", "\\.").replace("rparen", ".paren") + + ")+" + ); + } + + // Start searching in token, just before the character at position.column + var valueIndex = position.column - iterator.getCurrentTokenColumn() - 2; + var value = token.value; + + while (true) { + + while (valueIndex >= 0) { + var chr = value.charAt(valueIndex); + if (chr == openBracket) { + depth -= 1; + if (depth == 0) { + return {row: iterator.getCurrentTokenRow(), + column: valueIndex + iterator.getCurrentTokenColumn()}; + } + } + else if (chr == bracket) { + depth += 1; + } + valueIndex -= 1; + } + + // Scan backward through the document, looking for the next token + // whose type matches typeRe + do { + token = iterator.stepBackward(); + } while (token && !typeRe.test(token.type)); + + if (token == null) + break; + + value = token.value; + valueIndex = value.length - 1; + } + + return null; + }; + + this.$findClosingBracket = function(bracket, position, typeRe) { + var closingBracket = this.$brackets[bracket]; + var depth = 1; + + var iterator = new TokenIterator(this, position.row, position.column); + var token = iterator.getCurrentToken(); + if (!token) + token = iterator.stepForward(); + if (!token) + return; + + if (!typeRe){ + typeRe = new RegExp( + "(\\.?" + + token.type.replace(".", "\\.").replace("lparen", ".paren") + + ")+" + ); + } + + // Start searching in token, after the character at position.column + var valueIndex = position.column - iterator.getCurrentTokenColumn(); + + while (true) { + + var value = token.value; + var valueLength = value.length; + while (valueIndex < valueLength) { + var chr = value.charAt(valueIndex); + if (chr == closingBracket) { + depth -= 1; + if (depth == 0) { + return {row: iterator.getCurrentTokenRow(), + column: valueIndex + iterator.getCurrentTokenColumn()}; + } + } + else if (chr == bracket) { + depth += 1; + } + valueIndex += 1; + } + + // Scan forward through the document, looking for the next token + // whose type matches typeRe + do { + token = iterator.stepForward(); + } while (token && !typeRe.test(token.type)); + + if (token == null) + break; + + valueIndex = 0; + } + + return null; + }; +} +exports.BracketMatch = BracketMatch; + +}); diff --git a/lib/ace/edit_session/fold.js b/lib/ace/edit_session/fold.js new file mode 100644 index 0000000000..3a66f9c5f4 --- /dev/null +++ b/lib/ace/edit_session/fold.js @@ -0,0 +1,108 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +/* + * Simple fold-data struct. + **/ +var Fold = exports.Fold = function(range, placeholder) { + this.foldLine = null; + this.placeholder = placeholder; + this.range = range; + this.start = range.start; + this.end = range.end; + + this.sameRow = range.start.row == range.end.row; + this.subFolds = []; +}; + +(function() { + + this.toString = function() { + return '"' + this.placeholder + '" ' + this.range.toString(); + }; + + this.setFoldLine = function(foldLine) { + this.foldLine = foldLine; + this.subFolds.forEach(function(fold) { + fold.setFoldLine(foldLine); + }); + }; + + this.clone = function() { + var range = this.range.clone(); + var fold = new Fold(range, this.placeholder); + this.subFolds.forEach(function(subFold) { + fold.subFolds.push(subFold.clone()); + }); + return fold; + }; + + this.addSubFold = function(fold) { + if (this.range.isEqual(fold)) + return this; + + if (!this.range.containsRange(fold)) + throw "A fold can't intersect already existing fold" + fold.range + this.range; + + var row = fold.range.start.row, column = fold.range.start.column; + for (var i = 0, cmp = -1; i < this.subFolds.length; i++) { + cmp = this.subFolds[i].range.compare(row, column); + if (cmp != 1) + break; + } + var afterStart = this.subFolds[i]; + + if (cmp == 0) + return afterStart.addSubFold(fold); + + // cmp == -1 + var row = fold.range.end.row, column = fold.range.end.column; + for (var j = i, cmp = -1; j < this.subFolds.length; j++) { + cmp = this.subFolds[j].range.compare(row, column); + if (cmp != 1) + break; + } + var afterEnd = this.subFolds[j]; + + if (cmp == 0) + throw "A fold can't intersect already existing fold" + fold.range + this.range; + + var consumedFolds = this.subFolds.splice(i, j - i, fold); + fold.setFoldLine(this.foldLine); + + return fold; + }; + +}).call(Fold.prototype); + +}); diff --git a/lib/ace/edit_session/fold_line.js b/lib/ace/edit_session/fold_line.js new file mode 100644 index 0000000000..cec3eb4c6d --- /dev/null +++ b/lib/ace/edit_session/fold_line.js @@ -0,0 +1,268 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var Range = require("../range").Range; + +/* + * If an array is passed in, the folds are expected to be sorted already. + */ +function FoldLine(foldData, folds) { + this.foldData = foldData; + if (Array.isArray(folds)) { + this.folds = folds; + } else { + folds = this.folds = [ folds ]; + } + + var last = folds[folds.length - 1] + this.range = new Range(folds[0].start.row, folds[0].start.column, + last.end.row, last.end.column); + this.start = this.range.start; + this.end = this.range.end; + + this.folds.forEach(function(fold) { + fold.setFoldLine(this); + }, this); +} + +(function() { + /* + * Note: This doesn't update wrapData! + */ + this.shiftRow = function(shift) { + this.start.row += shift; + this.end.row += shift; + this.folds.forEach(function(fold) { + fold.start.row += shift; + fold.end.row += shift; + }); + } + + this.addFold = function(fold) { + if (fold.sameRow) { + if (fold.start.row < this.startRow || fold.endRow > this.endRow) { + throw "Can't add a fold to this FoldLine as it has no connection"; + } + this.folds.push(fold); + this.folds.sort(function(a, b) { + return -a.range.compareEnd(b.start.row, b.start.column); + }); + if (this.range.compareEnd(fold.start.row, fold.start.column) > 0) { + this.end.row = fold.end.row; + this.end.column = fold.end.column; + } else if (this.range.compareStart(fold.end.row, fold.end.column) < 0) { + this.start.row = fold.start.row; + this.start.column = fold.start.column; + } + } else if (fold.start.row == this.end.row) { + this.folds.push(fold); + this.end.row = fold.end.row; + this.end.column = fold.end.column; + } else if (fold.end.row == this.start.row) { + this.folds.unshift(fold); + this.start.row = fold.start.row; + this.start.column = fold.start.column; + } else { + throw "Trying to add fold to FoldRow that doesn't have a matching row"; + } + fold.foldLine = this; + } + + this.containsRow = function(row) { + return row >= this.start.row && row <= this.end.row; + } + + this.walk = function(callback, endRow, endColumn) { + var lastEnd = 0, + folds = this.folds, + fold, + comp, stop, isNewRow = true; + + if (endRow == null) { + endRow = this.end.row; + endColumn = this.end.column; + } + + for (var i = 0; i < folds.length; i++) { + fold = folds[i]; + + comp = fold.range.compareStart(endRow, endColumn); + // This fold is after the endRow/Column. + if (comp == -1) { + callback(null, endRow, endColumn, lastEnd, isNewRow); + return; + } + + stop = callback(null, fold.start.row, fold.start.column, lastEnd, isNewRow); + stop = !stop && callback(fold.placeholder, fold.start.row, fold.start.column, lastEnd); + + // If the user requested to stop the walk or endRow/endColumn is + // inside of this fold (comp == 0), then end here. + if (stop || comp == 0) { + return; + } + + // Note the new lastEnd might not be on the same line. However, + // it's the callback's job to recognize this. + isNewRow = !fold.sameRow; + lastEnd = fold.end.column; + } + callback(null, endRow, endColumn, lastEnd, isNewRow); + } + + this.getNextFoldTo = function(row, column) { + var fold, cmp; + for (var i = 0; i < this.folds.length; i++) { + fold = this.folds[i]; + cmp = fold.range.compareEnd(row, column); + if (cmp == -1) { + return { + fold: fold, + kind: "after" + }; + } else if (cmp == 0) { + return { + fold: fold, + kind: "inside" + } + } + } + return null; + } + + this.addRemoveChars = function(row, column, len) { + var ret = this.getNextFoldTo(row, column), + fold, folds; + if (ret) { + fold = ret.fold; + if (ret.kind == "inside" + && fold.start.column != column + && fold.start.row != row) + { + //throwing here breaks whole editor + //TODO: properly handle this + window.console && window.console.log(row, column, fold); + } else if (fold.start.row == row) { + folds = this.folds; + var i = folds.indexOf(fold); + if (i == 0) { + this.start.column += len; + } + for (i; i < folds.length; i++) { + fold = folds[i]; + fold.start.column += len; + if (!fold.sameRow) { + return; + } + fold.end.column += len; + } + this.end.column += len; + } + } + } + + this.split = function(row, column) { + var fold = this.getNextFoldTo(row, column).fold, + folds = this.folds; + var foldData = this.foldData; + + if (!fold) { + return null; + } + var i = folds.indexOf(fold); + var foldBefore = folds[i - 1]; + this.end.row = foldBefore.end.row; + this.end.column = foldBefore.end.column; + + // Remove the folds after row/column and create a new FoldLine + // containing these removed folds. + folds = folds.splice(i, folds.length - i); + + var newFoldLine = new FoldLine(foldData, folds); + foldData.splice(foldData.indexOf(this) + 1, 0, newFoldLine); + return newFoldLine; + } + + this.merge = function(foldLineNext) { + var folds = foldLineNext.folds; + for (var i = 0; i < folds.length; i++) { + this.addFold(folds[i]); + } + // Remove the foldLineNext - no longer needed, as + // it's merged now with foldLineNext. + var foldData = this.foldData; + foldData.splice(foldData.indexOf(foldLineNext), 1); + } + + this.toString = function() { + var ret = [this.range.toString() + ": [" ]; + + this.folds.forEach(function(fold) { + ret.push(" " + fold.toString()); + }); + ret.push("]") + return ret.join("\n"); + } + + this.idxToPosition = function(idx) { + var lastFoldEndColumn = 0; + var fold; + + for (var i = 0; i < this.folds.length; i++) { + var fold = this.folds[i]; + + idx -= fold.start.column - lastFoldEndColumn; + if (idx < 0) { + return { + row: fold.start.row, + column: fold.start.column + idx + }; + } + + idx -= fold.placeholder.length; + if (idx < 0) { + return fold.start; + } + + lastFoldEndColumn = fold.end.column; + } + + return { + row: this.end.row, + column: this.end.column + idx + }; + } +}).call(FoldLine.prototype); + +exports.FoldLine = FoldLine; +}); diff --git a/lib/ace/edit_session/folding.js b/lib/ace/edit_session/folding.js new file mode 100644 index 0000000000..f3029c1865 --- /dev/null +++ b/lib/ace/edit_session/folding.js @@ -0,0 +1,751 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var Range = require("../range").Range; +var FoldLine = require("./fold_line").FoldLine; +var Fold = require("./fold").Fold; +var TokenIterator = require("../token_iterator").TokenIterator; + +function Folding() { + /* + * Looks up a fold at a given row/column. Possible values for side: + * -1: ignore a fold if fold.start = row/column + * +1: ignore a fold if fold.end = row/column + */ + this.getFoldAt = function(row, column, side) { + var foldLine = this.getFoldLine(row); + if (!foldLine) + return null; + + var folds = foldLine.folds; + for (var i = 0; i < folds.length; i++) { + var fold = folds[i]; + if (fold.range.contains(row, column)) { + if (side == 1 && fold.range.isEnd(row, column)) { + continue; + } else if (side == -1 && fold.range.isStart(row, column)) { + continue; + } + return fold; + } + } + }; + + /* + * Returns all folds in the given range. Note, that this will return folds + * + */ + this.getFoldsInRange = function(range) { + range = range.clone(); + var start = range.start; + var end = range.end; + var foldLines = this.$foldData; + var foundFolds = []; + + start.column += 1; + end.column -= 1; + + for (var i = 0; i < foldLines.length; i++) { + var cmp = foldLines[i].range.compareRange(range); + if (cmp == 2) { + // Range is before foldLine. No intersection. This means, + // there might be other foldLines that intersect. + continue; + } + else if (cmp == -2) { + // Range is after foldLine. There can't be any other foldLines then, + // so let's give up. + break; + } + + var folds = foldLines[i].folds; + for (var j = 0; j < folds.length; j++) { + var fold = folds[j]; + cmp = fold.range.compareRange(range); + if (cmp == -2) { + break; + } else if (cmp == 2) { + continue; + } else + // WTF-state: Can happen due to -1/+1 to start/end column. + if (cmp == 42) { + break; + } + foundFolds.push(fold); + } + } + return foundFolds; + }; + + /* + * Returns all folds in the document + */ + this.getAllFolds = function() { + var folds = []; + var foldLines = this.$foldData; + + function addFold(fold) { + folds.push(fold); + if (!fold.subFolds) + return; + + for (var i = 0; i < fold.subFolds.length; i++) + addFold(fold.subFolds[i]); + } + + for (var i = 0; i < foldLines.length; i++) + for (var j = 0; j < foldLines[i].folds.length; j++) + addFold(foldLines[i].folds[j]); + + return folds; + }; + + /* + * Returns the string between folds at the given position. + * E.g. + * foob|arwolrd -> "bar" + * foobarwol|rd -> "world" + * foobarwolrd -> + * + * where | means the position of row/column + * + * The trim option determs if the return string should be trimed according + * to the "side" passed with the trim value: + * + * E.g. + * foob|arwolrd -trim=-1> "b" + * foobarwol|rd -trim=+1> "rld" + * fo|obarwolrd -trim=00> "foo" + */ + this.getFoldStringAt = function(row, column, trim, foldLine) { + foldLine = foldLine || this.getFoldLine(row); + if (!foldLine) + return null; + + var lastFold = { + end: { column: 0 } + }; + // TODO: Refactor to use getNextFoldTo function. + var str, fold; + for (var i = 0; i < foldLine.folds.length; i++) { + fold = foldLine.folds[i]; + var cmp = fold.range.compareEnd(row, column); + if (cmp == -1) { + str = this + .getLine(fold.start.row) + .substring(lastFold.end.column, fold.start.column); + break; + } + else if (cmp === 0) { + return null; + } + lastFold = fold; + } + if (!str) + str = this.getLine(fold.start.row).substring(lastFold.end.column); + + if (trim == -1) + return str.substring(0, column - lastFold.end.column); + else if (trim == 1) + return str.substring(column - lastFold.end.column); + else + return str; + }; + + this.getFoldLine = function(docRow, startFoldLine) { + var foldData = this.$foldData; + var i = 0; + if (startFoldLine) + i = foldData.indexOf(startFoldLine); + if (i == -1) + i = 0; + for (i; i < foldData.length; i++) { + var foldLine = foldData[i]; + if (foldLine.start.row <= docRow && foldLine.end.row >= docRow) { + return foldLine; + } else if (foldLine.end.row > docRow) { + return null; + } + } + return null; + }; + + // returns the fold which starts after or contains docRow + this.getNextFoldLine = function(docRow, startFoldLine) { + var foldData = this.$foldData; + var i = 0; + if (startFoldLine) + i = foldData.indexOf(startFoldLine); + if (i == -1) + i = 0; + for (i; i < foldData.length; i++) { + var foldLine = foldData[i]; + if (foldLine.end.row >= docRow) { + return foldLine; + } + } + return null; + }; + + this.getFoldedRowCount = function(first, last) { + var foldData = this.$foldData, rowCount = last-first+1; + for (var i = 0; i < foldData.length; i++) { + var foldLine = foldData[i], + end = foldLine.end.row, + start = foldLine.start.row; + if (end >= last) { + if(start < last) { + if(start >= first) + rowCount -= last-start; + else + rowCount = 0;//in one fold + } + break; + } else if(end >= first){ + if (start >= first) //fold inside range + rowCount -= end-start; + else + rowCount -= end-first+1; + } + } + return rowCount; + }; + + this.$addFoldLine = function(foldLine) { + this.$foldData.push(foldLine); + this.$foldData.sort(function(a, b) { + return a.start.row - b.start.row; + }); + return foldLine; + }; + + /* + * Adds a new fold. + * + * @returns + * The new created Fold object or an existing fold object in case the + * passed in range fits an existing fold exactly. + */ + this.addFold = function(placeholder, range) { + var foldData = this.$foldData; + var added = false; + var fold; + + if (placeholder instanceof Fold) + fold = placeholder; + else + fold = new Fold(range, placeholder); + + this.$clipRangeToDocument(fold.range); + + var startRow = fold.start.row; + var startColumn = fold.start.column; + var endRow = fold.end.row; + var endColumn = fold.end.column; + + // --- Some checking --- + if (startRow == endRow && endColumn - startColumn < 2) + throw "The range has to be at least 2 characters width"; + + var startFold = this.getFoldAt(startRow, startColumn, 1); + var endFold = this.getFoldAt(endRow, endColumn, -1); + if (startFold && endFold == startFold) + return startFold.addSubFold(fold); + + if ( + (startFold && !startFold.range.isStart(startRow, startColumn)) + || (endFold && !endFold.range.isEnd(endRow, endColumn)) + ) { + throw "A fold can't intersect already existing fold" + fold.range + startFold.range; + } + + // Check if there are folds in the range we create the new fold for. + var folds = this.getFoldsInRange(fold.range); + if (folds.length > 0) { + // Remove the folds from fold data. + this.removeFolds(folds); + // Add the removed folds as subfolds on the new fold. + fold.subFolds = folds; + } + + for (var i = 0; i < foldData.length; i++) { + var foldLine = foldData[i]; + if (endRow == foldLine.start.row) { + foldLine.addFold(fold); + added = true; + break; + } + else if (startRow == foldLine.end.row) { + foldLine.addFold(fold); + added = true; + if (!fold.sameRow) { + // Check if we might have to merge two FoldLines. + var foldLineNext = foldData[i + 1]; + if (foldLineNext && foldLineNext.start.row == endRow) { + // We need to merge! + foldLine.merge(foldLineNext); + break; + } + } + break; + } + else if (endRow <= foldLine.start.row) { + break; + } + } + + if (!added) + foldLine = this.$addFoldLine(new FoldLine(this.$foldData, fold)); + + if (this.$useWrapMode) + this.$updateWrapData(foldLine.start.row, foldLine.start.row); + else + this.$updateRowLengthCache(foldLine.start.row, foldLine.start.row); + + // Notify that fold data has changed. + this.$modified = true; + this._emit("changeFold", { data: fold }); + + return fold; + }; + + this.addFolds = function(folds) { + folds.forEach(function(fold) { + this.addFold(fold); + }, this); + }; + + this.removeFold = function(fold) { + var foldLine = fold.foldLine; + var startRow = foldLine.start.row; + var endRow = foldLine.end.row; + + var foldLines = this.$foldData; + var folds = foldLine.folds; + // Simple case where there is only one fold in the FoldLine such that + // the entire fold line can get removed directly. + if (folds.length == 1) { + foldLines.splice(foldLines.indexOf(foldLine), 1); + } else + // If the fold is the last fold of the foldLine, just remove it. + if (foldLine.range.isEnd(fold.end.row, fold.end.column)) { + folds.pop(); + foldLine.end.row = folds[folds.length - 1].end.row; + foldLine.end.column = folds[folds.length - 1].end.column; + } else + // If the fold is the first fold of the foldLine, just remove it. + if (foldLine.range.isStart(fold.start.row, fold.start.column)) { + folds.shift(); + foldLine.start.row = folds[0].start.row; + foldLine.start.column = folds[0].start.column; + } else + // We know there are more then 2 folds and the fold is not at the edge. + // This means, the fold is somewhere in between. + // + // If the fold is in one row, we just can remove it. + if (fold.sameRow) { + folds.splice(folds.indexOf(fold), 1); + } else + // The fold goes over more then one row. This means remvoing this fold + // will cause the fold line to get splitted up. newFoldLine is the second part + { + var newFoldLine = foldLine.split(fold.start.row, fold.start.column); + folds = newFoldLine.folds; + folds.shift(); + newFoldLine.start.row = folds[0].start.row; + newFoldLine.start.column = folds[0].start.column; + } + + if (this.$useWrapMode) + this.$updateWrapData(startRow, endRow); + else + this.$updateRowLengthCache(startRow, endRow); + + // Notify that fold data has changed. + this.$modified = true; + this._emit("changeFold", { data: fold }); + }; + + this.removeFolds = function(folds) { + // We need to clone the folds array passed in as it might be the folds + // array of a fold line and as we call this.removeFold(fold), folds + // are removed from folds and changes the current index. + var cloneFolds = []; + for (var i = 0; i < folds.length; i++) { + cloneFolds.push(folds[i]); + } + + cloneFolds.forEach(function(fold) { + this.removeFold(fold); + }, this); + this.$modified = true; + }; + + this.expandFold = function(fold) { + this.removeFold(fold); + fold.subFolds.forEach(function(fold) { + this.addFold(fold); + }, this); + fold.subFolds = []; + }; + + this.expandFolds = function(folds) { + folds.forEach(function(fold) { + this.expandFold(fold); + }, this); + }; + + this.unfold = function(location, expandInner) { + var range, folds; + if (location == null) + range = new Range(0, 0, this.getLength(), 0); + else if (typeof location == "number") + range = new Range(location, 0, location, this.getLine(location).length); + else if ("row" in location) + range = Range.fromPoints(location, location); + else + range = location; + + folds = this.getFoldsInRange(range); + if (expandInner) { + this.removeFolds(folds); + } else { + // TODO: might need to remove and add folds in one go instead of using + // expandFolds several times. + while (folds.length) { + this.expandFolds(folds); + folds = this.getFoldsInRange(range); + } + } + }; + + /* + * Checks if a given documentRow is folded. This is true if there are some + * folded parts such that some parts of the line is still visible. + **/ + this.isRowFolded = function(docRow, startFoldRow) { + return !!this.getFoldLine(docRow, startFoldRow); + }; + + this.getRowFoldEnd = function(docRow, startFoldRow) { + var foldLine = this.getFoldLine(docRow, startFoldRow); + return foldLine ? foldLine.end.row : docRow; + }; + + this.getFoldDisplayLine = function(foldLine, endRow, endColumn, startRow, startColumn) { + if (startRow == null) { + startRow = foldLine.start.row; + startColumn = 0; + } + + if (endRow == null) { + endRow = foldLine.end.row; + endColumn = this.getLine(endRow).length; + } + + // Build the textline using the FoldLine walker. + var doc = this.doc; + var textLine = ""; + + foldLine.walk(function(placeholder, row, column, lastColumn) { + if (row < startRow) { + return; + } else if (row == startRow) { + if (column < startColumn) { + return; + } + lastColumn = Math.max(startColumn, lastColumn); + } + if (placeholder != null) { + textLine += placeholder; + } else { + textLine += doc.getLine(row).substring(lastColumn, column); + } + }.bind(this), endRow, endColumn); + return textLine; + }; + + this.getDisplayLine = function(row, endColumn, startRow, startColumn) { + var foldLine = this.getFoldLine(row); + + if (!foldLine) { + var line; + line = this.doc.getLine(row); + return line.substring(startColumn || 0, endColumn || line.length); + } else { + return this.getFoldDisplayLine( + foldLine, row, endColumn, startRow, startColumn); + } + }; + + this.$cloneFoldData = function() { + var fd = []; + fd = this.$foldData.map(function(foldLine) { + var folds = foldLine.folds.map(function(fold) { + return fold.clone(); + }); + return new FoldLine(fd, folds); + }); + + return fd; + }; + + this.toggleFold = function(tryToUnfold) { + var selection = this.selection; + var range = selection.getRange(); + var fold; + var bracketPos; + + if (range.isEmpty()) { + var cursor = range.start; + fold = this.getFoldAt(cursor.row, cursor.column); + + if (fold) { + this.expandFold(fold); + return; + } + else if (bracketPos = this.findMatchingBracket(cursor)) { + if (range.comparePoint(bracketPos) == 1) { + range.end = bracketPos; + } + else { + range.start = bracketPos; + range.start.column++; + range.end.column--; + } + } + else if (bracketPos = this.findMatchingBracket({row: cursor.row, column: cursor.column + 1})) { + if (range.comparePoint(bracketPos) == 1) + range.end = bracketPos; + else + range.start = bracketPos; + + range.start.column++; + } + else { + range = this.getCommentFoldRange(cursor.row, cursor.column) || range; + } + } else { + var folds = this.getFoldsInRange(range); + if (tryToUnfold && folds.length) { + this.expandFolds(folds); + return; + } + else if (folds.length == 1 ) { + fold = folds[0]; + } + } + + if (!fold) + fold = this.getFoldAt(range.start.row, range.start.column); + + if (fold && fold.range.toString() == range.toString()) { + this.expandFold(fold); + return; + } + + var placeholder = "..."; + if (!range.isMultiLine()) { + placeholder = this.getTextRange(range); + if(placeholder.length < 4) + return; + placeholder = placeholder.trim().substring(0, 2) + ".."; + } + + this.addFold(placeholder, range); + }; + + this.getCommentFoldRange = function(row, column, dir) { + var iterator = new TokenIterator(this, row, column); + var token = iterator.getCurrentToken(); + if (token && /^comment|string/.test(token.type)) { + var range = new Range(); + var re = new RegExp(token.type.replace(/\..*/, "\\.")); + if (dir != 1) { + do { + token = iterator.stepBackward(); + } while(token && re.test(token.type)); + iterator.stepForward(); + } + + range.start.row = iterator.getCurrentTokenRow(); + range.start.column = iterator.getCurrentTokenColumn() + 2; + + iterator = new TokenIterator(this, row, column); + + if (dir != -1) { + do { + token = iterator.stepForward(); + } while(token && re.test(token.type)); + token = iterator.stepBackward(); + } else + token = iterator.getCurrentToken(); + + range.end.row = iterator.getCurrentTokenRow(); + range.end.column = iterator.getCurrentTokenColumn() + token.value.length - 2; + return range; + } + }; + + this.foldAll = function(startRow, endRow) { + var foldWidgets = this.foldWidgets; + endRow = endRow || this.getLength(); + for (var row = startRow || 0; row < endRow; row++) { + if (foldWidgets[row] == null) + foldWidgets[row] = this.getFoldWidget(row); + if (foldWidgets[row] != "start") + continue; + + var range = this.getFoldWidgetRange(row); + // sometimes range can be incompatible with existing fold + // wouldn't it be better for addFold to return null istead of throwing? + if (range && range.end.row <= endRow) try { + this.addFold("...", range); + } catch(e) {} + } + }; + + this.$foldStyles = { + "manual": 1, + "markbegin": 1, + "markbeginend": 1 + }; + this.$foldStyle = "markbegin"; + this.setFoldStyle = function(style) { + if (!this.$foldStyles[style]) + throw new Error("invalid fold style: " + style + "[" + Object.keys(this.$foldStyles).join(", ") + "]"); + + if (this.$foldStyle == style) + return; + + this.$foldStyle = style; + + if (style == "manual") + this.unfold(); + + // reset folding + var mode = this.$foldMode; + this.$setFolding(null); + this.$setFolding(mode); + }; + + // structured folding + this.$setFolding = function(foldMode) { + if (this.$foldMode == foldMode) + return; + + this.$foldMode = foldMode; + + this.removeListener('change', this.$updateFoldWidgets); + this._emit("changeAnnotation"); + + if (!foldMode || this.$foldStyle == "manual") { + this.foldWidgets = null; + return; + } + + this.foldWidgets = []; + this.getFoldWidget = foldMode.getFoldWidget.bind(foldMode, this, this.$foldStyle); + this.getFoldWidgetRange = foldMode.getFoldWidgetRange.bind(foldMode, this, this.$foldStyle); + + this.$updateFoldWidgets = this.updateFoldWidgets.bind(this); + this.on('change', this.$updateFoldWidgets); + + }; + + this.onFoldWidgetClick = function(row, e) { + e = e.domEvent; + var type = this.getFoldWidget(row); + var line = this.getLine(row); + var onlySubfolds = e.shiftKey; + var addSubfolds = onlySubfolds || e.ctrlKey || e.altKey || e.metaKey; + var fold; + + if (type == "end") + fold = this.getFoldAt(row, 0, -1); + else + fold = this.getFoldAt(row, line.length, 1); + + if (fold) { + if (addSubfolds) + this.removeFold(fold); + else + this.expandFold(fold); + return; + } + + var range = this.getFoldWidgetRange(row); + if (range) { + // sometimes singleline folds can be missed by the code above + if (!range.isMultiLine()) { + fold = this.getFoldAt(range.start.row, range.start.column, 1); + if (fold && range.isEqual(fold.range)) { + this.removeFold(fold); + return; + } + } + + if (!onlySubfolds) + this.addFold("...", range); + + if (addSubfolds) + this.foldAll(range.start.row + 1, range.end.row); + } else { + if (addSubfolds) + this.foldAll(row + 1, this.getLength()); + (e.target || e.srcElement).className += " ace_invalid" + } + }; + + this.updateFoldWidgets = function(e) { + var delta = e.data; + var range = delta.range; + var firstRow = range.start.row; + var len = range.end.row - firstRow; + + if (len === 0) { + this.foldWidgets[firstRow] = null; + } else if (delta.action == "removeText" || delta.action == "removeLines") { + this.foldWidgets.splice(firstRow, len + 1, null); + } else { + var args = Array(len + 1); + args.unshift(firstRow, 1); + this.foldWidgets.splice.apply(this.foldWidgets, args); + } + }; + +} + +exports.Folding = Folding; + +}); diff --git a/lib/ace/edit_session_test.js b/lib/ace/edit_session_test.js new file mode 100644 index 0000000000..e89ad57f1c --- /dev/null +++ b/lib/ace/edit_session_test.js @@ -0,0 +1,1001 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); + require("./test/mockdom"); +} + +define(function(require, exports, module) { +"use strict"; + +var lang = require("./lib/lang"); +var EditSession = require("./edit_session").EditSession; +var Editor = require("./editor").Editor; +var UndoManager = require("./undomanager").UndoManager; +var MockRenderer = require("./test/mockrenderer").MockRenderer; +var Range = require("./range").Range; +var assert = require("./test/assertions"); +var JavaScriptMode = require("./mode/javascript").Mode; + +function createFoldTestSession() { + var lines = [ + "function foo(items) {", + " for (var i=0; i>", [1, 2], 1); + }, + + "test get longest line" : function() { + var session = new EditSession(["12"]); + session.setTabSize(4); + assert.equal(session.getScreenWidth(), 2); + + session.doc.insertNewLine({row: 0, column: Infinity}); + session.doc.insertLines(1, ["123"]); + assert.equal(session.getScreenWidth(), 3); + + session.doc.insertNewLine({row: 0, column: Infinity}); + session.doc.insertLines(1, ["\t\t"]); + + assert.equal(session.getScreenWidth(), 8); + + session.setTabSize(2); + assert.equal(session.getScreenWidth(), 4); + }, + + "test getDisplayString": function() { + var session = new EditSession(["12"]); + session.setTabSize(4); + + assert.equal(session.$getDisplayTokens("\t").length, 4); + assert.equal(session.$getDisplayTokens("abc").length, 3); + assert.equal(session.$getDisplayTokens("abc\t").length, 4); + }, + + "test issue 83": function() { + var session = new EditSession(""); + var editor = new Editor(new MockRenderer(), session); + var document = session.getDocument(); + + session.setUseWrapMode(true); + + document.insertLines(0, ["a", "b"]); + document.insertLines(2, ["c", "d"]); + document.removeLines(1, 2); + }, + + "test wrapMode init has to create wrapData array": function() { + var session = new EditSession("foo bar\nfoo bar"); + var editor = new Editor(new MockRenderer(), session); + var document = session.getDocument(); + + session.setUseWrapMode(true); + session.setWrapLimitRange(3, 3); + session.adjustWrapLimit(80); + + // Test if wrapData is there and was computed. + assert.equal(session.$wrapData.length, 2); + assert.equal(session.$wrapData[0].length, 1); + assert.equal(session.$wrapData[1].length, 1); + }, + + "test first line blank with wrap": function() { + var session = new EditSession("\nfoo"); + session.setUseWrapMode(true); + assert.equal(session.doc.getValue(), ["", "foo"].join("\n")); + }, + + "test first line blank with wrap 2" : function() { + var session = new EditSession(""); + session.setUseWrapMode(true); + session.setValue("\nfoo"); + + assert.equal(session.doc.getValue(), ["", "foo"].join("\n")); + }, + + "test fold getFoldDisplayLine": function() { + var session = createFoldTestSession(); + function assertDisplayLine(foldLine, str) { + var line = session.getLine(foldLine.end.row); + var displayLine = + session.getFoldDisplayLine(foldLine, foldLine.end.row, line.length); + assert.equal(displayLine, str); + } + + assertDisplayLine(session.$foldData[0], "function foo(args...) {") + assertDisplayLine(session.$foldData[1], " for (vfoo...ert(items[bar...\"juhu\");"); + }, + + "test foldLine idxToPosition": function() { + var session = createFoldTestSession(); + + function assertIdx2Pos(foldLineIdx, idx, row, column) { + var foldLine = session.$foldData[foldLineIdx]; + assert.position(foldLine.idxToPosition(idx), row, column); + } + +// "function foo(items) {", +// " for (var i=0; i String + * + * Returns the keyboard handler. + **/ + this.getKeyboardHandler = function() { + return this.keyBinding.getKeyboardHandler(); + }; + + /** + * Editor.setSession(session) + * - session (EditSession): The new session to use + * + * Sets a new editsession to use. This method also emits the `'changeSession'` event. + **/ + /** + * Editor@changeSession(e) + * - e (Object): An object with two properties, `oldSession` and `session`, that represent the old and new [[EditSession]]s. + * + * Emitted whenever the [[EditSession]] changes. + **/ + this.setSession = function(session) { + if (this.session == session) + return; + + if (this.session) { + var oldSession = this.session; + this.session.removeEventListener("change", this.$onDocumentChange); + this.session.removeEventListener("changeMode", this.$onChangeMode); + this.session.removeEventListener("tokenizerUpdate", this.$onTokenizerUpdate); + this.session.removeEventListener("changeTabSize", this.$onChangeTabSize); + this.session.removeEventListener("changeWrapLimit", this.$onChangeWrapLimit); + this.session.removeEventListener("changeWrapMode", this.$onChangeWrapMode); + this.session.removeEventListener("onChangeFold", this.$onChangeFold); + this.session.removeEventListener("changeFrontMarker", this.$onChangeFrontMarker); + this.session.removeEventListener("changeBackMarker", this.$onChangeBackMarker); + this.session.removeEventListener("changeBreakpoint", this.$onChangeBreakpoint); + this.session.removeEventListener("changeAnnotation", this.$onChangeAnnotation); + this.session.removeEventListener("changeOverwrite", this.$onCursorChange); + this.session.removeEventListener("changeScrollTop", this.$onScrollTopChange); + this.session.removeEventListener("changeLeftTop", this.$onScrollLeftChange); + + var selection = this.session.getSelection(); + selection.removeEventListener("changeCursor", this.$onCursorChange); + selection.removeEventListener("changeSelection", this.$onSelectionChange); + } + + this.session = session; + + this.$onDocumentChange = this.onDocumentChange.bind(this); + session.addEventListener("change", this.$onDocumentChange); + this.renderer.setSession(session); + + this.$onChangeMode = this.onChangeMode.bind(this); + session.addEventListener("changeMode", this.$onChangeMode); + + this.$onTokenizerUpdate = this.onTokenizerUpdate.bind(this); + session.addEventListener("tokenizerUpdate", this.$onTokenizerUpdate); + + this.$onChangeTabSize = this.renderer.onChangeTabSize.bind(this.renderer); + session.addEventListener("changeTabSize", this.$onChangeTabSize); + + this.$onChangeWrapLimit = this.onChangeWrapLimit.bind(this); + session.addEventListener("changeWrapLimit", this.$onChangeWrapLimit); + + this.$onChangeWrapMode = this.onChangeWrapMode.bind(this); + session.addEventListener("changeWrapMode", this.$onChangeWrapMode); + + this.$onChangeFold = this.onChangeFold.bind(this); + session.addEventListener("changeFold", this.$onChangeFold); + + this.$onChangeFrontMarker = this.onChangeFrontMarker.bind(this); + this.session.addEventListener("changeFrontMarker", this.$onChangeFrontMarker); + + this.$onChangeBackMarker = this.onChangeBackMarker.bind(this); + this.session.addEventListener("changeBackMarker", this.$onChangeBackMarker); + + this.$onChangeBreakpoint = this.onChangeBreakpoint.bind(this); + this.session.addEventListener("changeBreakpoint", this.$onChangeBreakpoint); + + this.$onChangeAnnotation = this.onChangeAnnotation.bind(this); + this.session.addEventListener("changeAnnotation", this.$onChangeAnnotation); + + this.$onCursorChange = this.onCursorChange.bind(this); + this.session.addEventListener("changeOverwrite", this.$onCursorChange); + + this.$onScrollTopChange = this.onScrollTopChange.bind(this); + this.session.addEventListener("changeScrollTop", this.$onScrollTopChange); + + this.$onScrollLeftChange = this.onScrollLeftChange.bind(this); + this.session.addEventListener("changeScrollLeft", this.$onScrollLeftChange); + + this.selection = session.getSelection(); + this.selection.addEventListener("changeCursor", this.$onCursorChange); + + this.$onSelectionChange = this.onSelectionChange.bind(this); + this.selection.addEventListener("changeSelection", this.$onSelectionChange); + + this.onChangeMode(); + + this.$blockScrolling += 1; + this.onCursorChange(); + this.$blockScrolling -= 1; + + this.onScrollTopChange(); + this.onScrollLeftChange(); + this.onSelectionChange(); + this.onChangeFrontMarker(); + this.onChangeBackMarker(); + this.onChangeBreakpoint(); + this.onChangeAnnotation(); + this.session.getUseWrapMode() && this.renderer.adjustWrapLimit(); + this.renderer.updateFull(); + + this._emit("changeSession", { + session: session, + oldSession: oldSession + }); + }; + + /** + * Editor.getSession() -> EditSession + * + * Returns the current session being used. + **/ + this.getSession = function() { + return this.session; + }; + + /** related to: Document.setValue + * Editor.setValue(val [,cursorPos]) -> String + * - val (String): The new value to set for the document + * - cursorPos (Number): Where to set the new value. `undefined` or 0 is selectAll, -1 is at the document start, and 1 is at the end + * + * Sets the current document to `val`. + **/ + this.setValue = function(val, cursorPos) { + this.session.doc.setValue(val); + + if (!cursorPos) + this.selectAll(); + else if (cursorPos == 1) + this.navigateFileEnd(); + else if (cursorPos == -1) + this.navigateFileStart(); + + return val; + }; + + /** related to: EditSession.getValue + * Editor.getValue() -> String + * + * Returns the current session's content. + **/ + this.getValue = function() { + return this.session.getValue(); + }; + + /** + * Editor.getSelection() -> String + * + * Returns the currently highlighted selection. + **/ + this.getSelection = function() { + return this.selection; + }; + + /** related to: VirtualRenderer.onResize + * Editor.resize(force) + * - force (Boolean): If `true`, recomputes the size, even if the height and width haven't changed + * + * {:VirtualRenderer.onResize} + **/ + this.resize = function(force) { + this.renderer.onResize(force); + }; + + /** + * Editor.setTheme(theme) + * - theme (String): The path to a theme + * + * {:VirtualRenderer.setTheme} + **/ + this.setTheme = function(theme) { + this.renderer.setTheme(theme); + }; + + /** related to: VirtualRenderer.getTheme + * Editor.getTheme() -> String + * + * {:VirtualRenderer.getTheme} + **/ + this.getTheme = function() { + return this.renderer.getTheme(); + }; + + /** related to: VirtualRenderer.setStyle + * Editor.setStyle(style) + * - style (String): A class name + * + * {:VirtualRenderer.setStyle} + **/ + this.setStyle = function(style) { + this.renderer.setStyle(style); + }; + + /** related to: VirtualRenderer.unsetStyle + * Editor.unsetStyle(style) + * + * {:VirtualRenderer.unsetStyle} + **/ + this.unsetStyle = function(style) { + this.renderer.unsetStyle(style); + }; + + /** + * Editor.setFontSize(size) + * - size (Number): A font size + * + * Set a new font size (in pixels) for the editor text. + **/ + this.setFontSize = function(size) { + this.container.style.fontSize = size; + this.renderer.updateFontSize(); + }; + + /** internal, hide + * Editor.$highlightBrackets() + * + **/ + this.$highlightBrackets = function() { + if (this.session.$bracketHighlight) { + this.session.removeMarker(this.session.$bracketHighlight); + this.session.$bracketHighlight = null; + } + + if (this.$highlightPending) { + return; + } + + // perform highlight async to not block the browser during navigation + var self = this; + this.$highlightPending = true; + setTimeout(function() { + self.$highlightPending = false; + + var pos = self.session.findMatchingBracket(self.getCursorPosition()); + if (pos) { + var range = new Range(pos.row, pos.column, pos.row, pos.column+1); + self.session.$bracketHighlight = self.session.addMarker(range, "ace_bracket", "text"); + } + }, 50); + }; + + /** + * Editor.focus() + * + * Brings the current `textInput` into focus. + **/ + this.focus = function() { + // Safari needs the timeout + // iOS and Firefox need it called immediately + // to be on the save side we do both + var _self = this; + setTimeout(function() { + _self.textInput.focus(); + }); + this.textInput.focus(); + }; + + /** + * Editor.isFocused() -> Boolean + * + * Returns true if the current `textInput` is in focus. + **/ + this.isFocused = function() { + return this.textInput.isFocused(); + }; + + /** + * Editor.blur() + * + * Blurs the current `textInput`. + **/ + this.blur = function() { + this.textInput.blur(); + }; + + /** + * Editor@focus() + * + * Emitted once the editor comes into focus. + **/ + this.onFocus = function() { + if (this.$isFocused) + return; + this.$isFocused = true; + this.renderer.showCursor(); + this.renderer.visualizeFocus(); + this._emit("focus"); + }; + + /** + * Editor@blur() + * + * Emitted once the editor has been blurred. + **/ + this.onBlur = function() { + if (!this.$isFocused) + return; + this.$isFocused = false; + this.renderer.hideCursor(); + this.renderer.visualizeBlur(); + this._emit("blur"); + }; + + this.$cursorChange = function() { + this.renderer.updateCursor(); + }; + + /** + * Editor@change(e) + * - e (Object): Contains a single property, `data`, which has the delta of changes + * + * Emitted whenever the document is changed. + * + **/ + this.onDocumentChange = function(e) { + var delta = e.data; + var range = delta.range; + var lastRow; + + if (range.start.row == range.end.row && delta.action != "insertLines" && delta.action != "removeLines") + lastRow = range.end.row; + else + lastRow = Infinity; + this.renderer.updateLines(range.start.row, lastRow); + + this._emit("change", e); + + // update cursor because tab characters can influence the cursor position + this.$cursorChange(); + }; + + this.onTokenizerUpdate = function(e) { + var rows = e.data; + this.renderer.updateLines(rows.first, rows.last); + }; + + + this.onScrollTopChange = function() { + this.renderer.scrollToY(this.session.getScrollTop()); + }; + + this.onScrollLeftChange = function() { + this.renderer.scrollToX(this.session.getScrollLeft()); + }; + + /** + * Editor@changeSelection() + * + * Emitted when the selection changes. + * + **/ + this.onCursorChange = function() { + this.$cursorChange(); + + if (!this.$blockScrolling) { + this.renderer.scrollCursorIntoView(); + } + + this.$highlightBrackets(); + this.$updateHighlightActiveLine(); + this._emit("changeSelection"); + }; + + /** internal, hide + * Editor.$updateHighlightActiveLine() + * + * + **/ + this.$updateHighlightActiveLine = function() { + var session = this.getSession(); + + var highlight; + if (this.$highlightActiveLine) { + if ((this.$selectionStyle != "line" || !this.selection.isMultiLine())) + highlight = this.getCursorPosition(); + } + + if (session.$highlightLineMarker && !highlight) { + session.removeMarker(session.$highlightLineMarker.id); + session.$highlightLineMarker = null; + } else if (!session.$highlightLineMarker && highlight) { + session.$highlightLineMarker = session.highlightLines(highlight.row, highlight.row, "ace_active-line"); + } else if (highlight) { + session.$highlightLineMarker.start.row = highlight.row; + session.$highlightLineMarker.end.row = highlight.row; + session._emit("changeBackMarker"); + } + }; + + this.onSelectionChange = function(e) { + var session = this.session; + + if (session.$selectionMarker) { + session.removeMarker(session.$selectionMarker); + } + session.$selectionMarker = null; + + if (!this.selection.isEmpty()) { + var range = this.selection.getRange(); + var style = this.getSelectionStyle(); + session.$selectionMarker = session.addMarker(range, "ace_selection", style); + } else { + this.$updateHighlightActiveLine(); + } + + var re = this.$highlightSelectedWord && this.$getSelectionHighLightRegexp() + this.session.highlight(re); + + this._emit("changeSelection"); + }; + + this.$getSelectionHighLightRegexp = function() { + var session = this.session; + + var selection = this.getSelectionRange(); + if (selection.isEmpty() || selection.isMultiLine()) + return; + + var startOuter = selection.start.column - 1; + var endOuter = selection.end.column + 1; + var line = session.getLine(selection.start.row); + var lineCols = line.length; + var needle = line.substring(Math.max(startOuter, 0), + Math.min(endOuter, lineCols)); + + // Make sure the outer characters are not part of the word. + if ((startOuter >= 0 && /^[\w\d]/.test(needle)) || + (endOuter <= lineCols && /[\w\d]$/.test(needle))) + return; + + needle = line.substring(selection.start.column, selection.end.column); + if (!/^[\w\d]+$/.test(needle)) + return; + + var re = this.$search.$assembleRegExp({ + wholeWord: true, + caseSensitive: true, + needle: needle + }); + + return re; + }; + + + this.onChangeFrontMarker = function() { + this.renderer.updateFrontMarkers(); + }; + + this.onChangeBackMarker = function() { + this.renderer.updateBackMarkers(); + }; + + + this.onChangeBreakpoint = function() { + this.renderer.updateBreakpoints(); + }; + + this.onChangeAnnotation = function() { + this.renderer.setAnnotations(this.session.getAnnotations()); + }; + + + this.onChangeMode = function() { + this.renderer.updateText(); + }; + + + this.onChangeWrapLimit = function() { + this.renderer.updateFull(); + }; + + this.onChangeWrapMode = function() { + this.renderer.onResize(true); + }; + + + this.onChangeFold = function() { + // Update the active line marker as due to folding changes the current + // line range on the screen might have changed. + this.$updateHighlightActiveLine(); + // TODO: This might be too much updating. Okay for now. + this.renderer.updateFull(); + }; + + /** + * Editor.getCopyText() -> String + * + * Returns the string of text currently highlighted. + **/ + /** + * Editor@copy(text) + * - text (String): The copied text + * + * Emitted when text is copied. + **/ + this.getCopyText = function() { + var text = ""; + if (!this.selection.isEmpty()) + text = this.session.getTextRange(this.getSelectionRange()); + + this._emit("copy", text); + return text; + }; + + /** + * Editor.onCopy() + * + * Called whenever a text "copy" happens. + **/ + this.onCopy = function() { + this.commands.exec("copy", this); + }; + + /** + * Editor.onCut() + * + * called whenever a text "cut" happens. + **/ + this.onCut = function() { + this.commands.exec("cut", this); + }; + + /** + * Editor.onPaste(text) + * - text (String): The pasted text + * + * Called whenever a text "paste" happens. + **/ + /** + * Editor@paste(text) + * - text (String): The pasted text + * + * Emitted when text is pasted. + **/ + this.onPaste = function(text) { + // todo this should change when paste becomes a command + if (this.$readOnly) + return; + this._emit("paste", text); + this.insert(text); + }; + + + this.execCommand = function(command, args) { + this.commands.exec(command, this, args); + }; + + /** + * Editor.insert(text) + * - text (String): The new text to add + * + * Inserts `text` into wherever the cursor is pointing. + **/ + this.insert = function(text) { + var session = this.session; + var mode = session.getMode(); + var cursor = this.getCursorPosition(); + + if (this.getBehavioursEnabled()) { + // Get a transform if the current mode wants one. + var transform = mode.transformAction(session.getState(cursor.row), 'insertion', this, session, text); + if (transform) + text = transform.text; + } + + text = text.replace("\t", this.session.getTabString()); + + // remove selected text + if (!this.selection.isEmpty()) { + cursor = this.session.remove(this.getSelectionRange()); + this.clearSelection(); + } + else if (this.session.getOverwrite()) { + var range = new Range.fromPoints(cursor, cursor); + range.end.column += text.length; + this.session.remove(range); + } + + this.clearSelection(); + + var start = cursor.column; + var lineState = session.getState(cursor.row); + var line = session.getLine(cursor.row); + var shouldOutdent = mode.checkOutdent(lineState, line, text); + var end = session.insert(cursor, text); + + if (transform && transform.selection) { + if (transform.selection.length == 2) { // Transform relative to the current column + this.selection.setSelectionRange( + new Range(cursor.row, start + transform.selection[0], + cursor.row, start + transform.selection[1])); + } else { // Transform relative to the current row. + this.selection.setSelectionRange( + new Range(cursor.row + transform.selection[0], + transform.selection[1], + cursor.row + transform.selection[2], + transform.selection[3])); + } + } + + // TODO disabled multiline auto indent + // possibly doing the indent before inserting the text + // if (cursor.row !== end.row) { + if (session.getDocument().isNewLine(text)) { + var lineIndent = mode.getNextLineIndent(lineState, line.slice(0, cursor.column), session.getTabString()); + + this.moveCursorTo(cursor.row+1, 0); + + var size = session.getTabSize(); + var minIndent = Number.MAX_VALUE; + + for (var row = cursor.row + 1; row <= end.row; ++row) { + var indent = 0; + + line = session.getLine(row); + for (var i = 0; i < line.length; ++i) + if (line.charAt(i) == '\t') + indent += size; + else if (line.charAt(i) == ' ') + indent += 1; + else + break; + if (/[^\s]/.test(line)) + minIndent = Math.min(indent, minIndent); + } + + for (var row = cursor.row + 1; row <= end.row; ++row) { + var outdent = minIndent; + + line = session.getLine(row); + for (var i = 0; i < line.length && outdent > 0; ++i) + if (line.charAt(i) == '\t') + outdent -= size; + else if (line.charAt(i) == ' ') + outdent -= 1; + session.remove(new Range(row, 0, row, i)); + } + session.indentRows(cursor.row + 1, end.row, lineIndent); + } + if (shouldOutdent) + mode.autoOutdent(lineState, session, cursor.row); + }; + + this.onTextInput = function(text) { + this.keyBinding.onTextInput(text); + }; + + this.onCommandKey = function(e, hashId, keyCode) { + this.keyBinding.onCommandKey(e, hashId, keyCode); + }; + + /** related to: EditSession.setOverwrite + * Editor.setOverwrite(overwrite) + * - overwrite (Boolean): Defines wheter or not to set overwrites + * + * Pass in `true` to enable overwrites in your session, or `false` to disable. If overwrites is enabled, any text you enter will type over any text after it. If the value of `overwrite` changes, this function also emites the `changeOverwrite` event. + * + **/ + this.setOverwrite = function(overwrite) { + this.session.setOverwrite(overwrite); + }; + + /** related to: EditSession.getOverwrite + * Editor.getOverwrite() -> Boolean + * + * Returns `true` if overwrites are enabled; `false` otherwise. + **/ + this.getOverwrite = function() { + return this.session.getOverwrite(); + }; + + /** related to: EditSession.toggleOverwrite + * Editor.toggleOverwrite() + * + * Sets the value of overwrite to the opposite of whatever it currently is. + **/ + this.toggleOverwrite = function() { + this.session.toggleOverwrite(); + }; + + /** + * Editor.setScrollSpeed(speed) + * - speed (Number): A value indicating the new speed + * + * Sets how fast the mouse scrolling should do. + * + **/ + this.setScrollSpeed = function(speed) { + this.$mouseHandler.setScrollSpeed(speed); + }; + + /** + * Editor.getScrollSpeed() -> Number + * + * Returns the value indicating how fast the mouse scroll speed is. + **/ + this.getScrollSpeed = function() { + return this.$mouseHandler.getScrollSpeed(); + }; + + /** + * Editor.setDragDelay(dragDelay) + * - dragDelay (Number): A value indicating the new delay + * + * Sets the delay (in milliseconds) of the mouse drag. + * + **/ + this.setDragDelay = function(dragDelay) { + this.$mouseHandler.setDragDelay(dragDelay); + }; + + /** + * Editor.getDragDelay() -> Number + * + * Returns the current mouse drag delay. + **/ + this.getDragDelay = function() { + return this.$mouseHandler.getDragDelay(); + }; + + this.$selectionStyle = "line"; + /** + * Editor.setSelectionStyle(style) + * - style (String): The new selection style + * + * Indicates how selections should occur. By default, selections are set to "line". This function also emits the `'changeSelectionStyle'` event. + * + **/ + /** + * Editor@changeSelectionStyle(data) + * - data (Object): Contains one property, `data`, which indicates the new selection style + * + * Emitted when the selection style changes, via [[Editor.setSelectionStyle]]. + * + **/ + this.setSelectionStyle = function(style) { + if (this.$selectionStyle == style) return; + + this.$selectionStyle = style; + this.onSelectionChange(); + this._emit("changeSelectionStyle", {data: style}); + }; + + /** + * Editor.getSelectionStyle() -> String + * + * Returns the current selection style. + **/ + this.getSelectionStyle = function() { + return this.$selectionStyle; + }; + + this.$highlightActiveLine = true; + + /** + * Editor.setHighlightActiveLine(shouldHighlight) + * - shouldHighlight (Boolean): Set to `true` to highlight the current line + * + * Determines whether or not the current line should be highlighted. + * + **/ + this.setHighlightActiveLine = function(shouldHighlight) { + if (this.$highlightActiveLine == shouldHighlight) + return; + + this.$highlightActiveLine = shouldHighlight; + this.$updateHighlightActiveLine(); + }; + + /** + * Editor.getHighlightActiveLine() -> Boolean + * + * Returns `true` if current lines are always highlighted. + **/ + this.getHighlightActiveLine = function() { + return this.$highlightActiveLine; + }; + + this.$highlightGutterLine = true; + this.setHighlightGutterLine = function(shouldHighlight) { + if (this.$highlightGutterLine == shouldHighlight) + return; + + this.renderer.setHighlightGutterLine(shouldHighlight); + this.$highlightGutterLine = shouldHighlight; + }; + + this.getHighlightGutterLine = function() { + return this.$highlightGutterLine; + }; + + this.$highlightSelectedWord = true; + /** + * Editor.setHighlightSelectedWord(shouldHighlight) + * - shouldHighlight (Boolean): Set to `true` to highlight the currently selected word + * + * Determines if the currently selected word should be highlighted. + **/ + this.setHighlightSelectedWord = function(shouldHighlight) { + if (this.$highlightSelectedWord == shouldHighlight) + return; + + this.$highlightSelectedWord = shouldHighlight; + this.$onSelectionChange(); + }; + + /** + * Editor.getHighlightSelectedWord() -> Boolean + * + * Returns `true` if currently highlighted words are to be highlighted. + **/ + this.getHighlightSelectedWord = function() { + return this.$highlightSelectedWord; + }; + + this.setAnimatedScroll = function(shouldAnimate){ + this.renderer.setAnimatedScroll(shouldAnimate); + }; + + this.getAnimatedScroll = function(){ + return this.renderer.getAnimatedScroll(); + }; + + /** + * Editor.setShowInvisibles(showInvisibles) + * - showInvisibles (Boolean): Specifies whether or not to show invisible characters + * + * If `showInvisibiles` is set to `true`, invisible characters—like spaces or new lines—are show in the editor. + **/ + this.setShowInvisibles = function(showInvisibles) { + this.renderer.setShowInvisibles(showInvisibles); + }; + + /** + * Editor.getShowInvisibles() -> Boolean + * + * Returns `true` if invisible characters are being shown. + **/ + this.getShowInvisibles = function() { + return this.renderer.getShowInvisibles(); + }; + + this.setDisplayIndentGuides = function(display) { + this.renderer.setDisplayIndentGuides(display); + }; + + this.getDisplayIndentGuides = function() { + return this.renderer.getDisplayIndentGuides(); + }; + + /** + * Editor.setShowPrintMargin(showPrintMargin) + * - showPrintMargin (Boolean): Specifies whether or not to show the print margin + * + * If `showPrintMargin` is set to `true`, the print margin is shown in the editor. + **/ + this.setShowPrintMargin = function(showPrintMargin) { + this.renderer.setShowPrintMargin(showPrintMargin); + }; + + /** + * Editor.getShowPrintMargin() -> Boolean + * + * Returns `true` if the print margin is being shown. + **/ + this.getShowPrintMargin = function() { + return this.renderer.getShowPrintMargin(); + }; + + /** + * Editor.setPrintMarginColumn(showPrintMargin) + * - showPrintMargin (Number): Specifies the new print margin + * + * Sets the column defining where the print margin should be. + * + **/ + this.setPrintMarginColumn = function(showPrintMargin) { + this.renderer.setPrintMarginColumn(showPrintMargin); + }; + + /** + * Editor.getPrintMarginColumn() -> Number + * + * Returns the column number of where the print margin is. + **/ + this.getPrintMarginColumn = function() { + return this.renderer.getPrintMarginColumn(); + }; + + this.$readOnly = false; + /** + * Editor.setReadOnly(readOnly) + * - readOnly (Boolean): Specifies whether the editor can be modified or not + * + * If `readOnly` is true, then the editor is set to read-only mode, and none of the content can change. + **/ + this.setReadOnly = function(readOnly) { + this.$readOnly = readOnly; + }; + + /** + * Editor.getReadOnly() -> Boolean + * + * Returns `true` if the editor is set to read-only mode. + **/ + this.getReadOnly = function() { + return this.$readOnly; + }; + + this.$modeBehaviours = true; + + /** + * Editor.setBehavioursEnabled(enabled) + * - enabled (Boolean): Enables or disables behaviors + * + * Specifies whether to use behaviors or not. ["Behaviors" in this case is the auto-pairing of special characters, like quotation marks, parenthesis, or brackets.]{: #BehaviorsDef} + **/ + this.setBehavioursEnabled = function (enabled) { + this.$modeBehaviours = enabled; + }; + + /** + * Editor.getBehavioursEnabled() -> Boolean + * + * Returns `true` if the behaviors are currently enabled. {:BehaviorsDef} + **/ + this.getBehavioursEnabled = function () { + return this.$modeBehaviours; + }; + + /** + * Editor.setShowFoldWidgets(show) + * - show (Boolean): Specifies whether the fold widgets are shown + * + * Indicates whether the fold widgets are shown or not. + **/ + this.setShowFoldWidgets = function(show) { + var gutter = this.renderer.$gutterLayer; + if (gutter.getShowFoldWidgets() == show) + return; + + this.renderer.$gutterLayer.setShowFoldWidgets(show); + this.$showFoldWidgets = show; + this.renderer.updateFull(); + }; + + /** + * Editor.getShowFoldWidgets() -> Boolean + * + * Returns `true` if the fold widgets are shown. + **/ + this.getShowFoldWidgets = function() { + return this.renderer.$gutterLayer.getShowFoldWidgets(); + }; + + this.setFadeFoldWidgets = function(show) { + this.renderer.setFadeFoldWidgets(show); + }; + + this.getFadeFoldWidgets = function() { + return this.renderer.getFadeFoldWidgets(); + }; + + /** + * Editor.remove(dir) + * - dir (String): The direction of the deletion to occur, either "left" or "right" + * + * Removes words of text from the editor. A "word" is defined as a string of characters bookended by whitespace. + * + **/ + this.remove = function(dir) { + if (this.selection.isEmpty()){ + if (dir == "left") + this.selection.selectLeft(); + else + this.selection.selectRight(); + } + + var range = this.getSelectionRange(); + if (this.getBehavioursEnabled()) { + var session = this.session; + var state = session.getState(range.start.row); + var new_range = session.getMode().transformAction(state, 'deletion', this, session, range); + if (new_range) + range = new_range; + } + + this.session.remove(range); + this.clearSelection(); + }; + + /** + * Editor.removeWordRight() + * + * Removes the word directly to the right of the current selection. + **/ + this.removeWordRight = function() { + if (this.selection.isEmpty()) + this.selection.selectWordRight(); + + this.session.remove(this.getSelectionRange()); + this.clearSelection(); + }; + + /** + * Editor.removeWordLeft() + * + * Removes the word directly to the left of the current selection. + **/ + this.removeWordLeft = function() { + if (this.selection.isEmpty()) + this.selection.selectWordLeft(); + + this.session.remove(this.getSelectionRange()); + this.clearSelection(); + }; + + /** + * Editor.removeToLineStart() + * + * Removes all the words to the left of the current selection, until the start of the line. + **/ + this.removeToLineStart = function() { + if (this.selection.isEmpty()) + this.selection.selectLineStart(); + + this.session.remove(this.getSelectionRange()); + this.clearSelection(); + }; + + /** + * Editor.removeToLineEnd() + * + * Removes all the words to the right of the current selection, until the end of the line. + **/ + this.removeToLineEnd = function() { + if (this.selection.isEmpty()) + this.selection.selectLineEnd(); + + var range = this.getSelectionRange(); + if (range.start.column == range.end.column && range.start.row == range.end.row) { + range.end.column = 0; + range.end.row++; + } + + this.session.remove(range); + this.clearSelection(); + }; + + /** + * Editor.splitLine() + * + * Splits the line at the current selection (by inserting an `'\n'`). + **/ + this.splitLine = function() { + if (!this.selection.isEmpty()) { + this.session.remove(this.getSelectionRange()); + this.clearSelection(); + } + + var cursor = this.getCursorPosition(); + this.insert("\n"); + this.moveCursorToPosition(cursor); + }; + + /** + * Editor.transposeLetters() + * + * Transposes current line. + **/ + this.transposeLetters = function() { + if (!this.selection.isEmpty()) { + return; + } + + var cursor = this.getCursorPosition(); + var column = cursor.column; + if (column === 0) + return; + + var line = this.session.getLine(cursor.row); + var swap, range; + if (column < line.length) { + swap = line.charAt(column) + line.charAt(column-1); + range = new Range(cursor.row, column-1, cursor.row, column+1); + } + else { + swap = line.charAt(column-1) + line.charAt(column-2); + range = new Range(cursor.row, column-2, cursor.row, column); + } + this.session.replace(range, swap); + }; + + /** + * Editor.toLowerCase() + * + * Converts the current selection entirely into lowercase. + **/ + this.toLowerCase = function() { + var originalRange = this.getSelectionRange(); + if (this.selection.isEmpty()) { + this.selection.selectWord(); + } + + var range = this.getSelectionRange(); + var text = this.session.getTextRange(range); + this.session.replace(range, text.toLowerCase()); + this.selection.setSelectionRange(originalRange); + }; + + /** + * Editor.toUpperCase() + * + * Converts the current selection entirely into uppercase. + **/ + this.toUpperCase = function() { + var originalRange = this.getSelectionRange(); + if (this.selection.isEmpty()) { + this.selection.selectWord(); + } + + var range = this.getSelectionRange(); + var text = this.session.getTextRange(range); + this.session.replace(range, text.toUpperCase()); + this.selection.setSelectionRange(originalRange); + }; + + /** related to: EditSession.indentRows + * Editor.indent() + * + * Indents the current line. + **/ + this.indent = function() { + var session = this.session; + var range = this.getSelectionRange(); + + if (range.start.row < range.end.row || range.start.column < range.end.column) { + var rows = this.$getSelectedRows(); + session.indentRows(rows.first, rows.last, "\t"); + } else { + var indentString; + + if (this.session.getUseSoftTabs()) { + var size = session.getTabSize(), + position = this.getCursorPosition(), + column = session.documentToScreenColumn(position.row, position.column), + count = (size - column % size); + + indentString = lang.stringRepeat(" ", count); + } else + indentString = "\t"; + return this.insert(indentString); + } + }; + + /** related to: EditSession.outdentRows + * Editor.blockOutdent() + * + * Outdents the current line. + **/ + this.blockOutdent = function() { + var selection = this.session.getSelection(); + this.session.outdentRows(selection.getRange()); + }; + + // TODO: move out of core when we have good mechanism for managing extensions + this.sortLines = function() { + var rows = this.$getSelectedRows(); + var session = this.session; + + var lines = []; + for (i = rows.first; i <= rows.last; i++) + lines.push(session.getLine(i)); + + lines.sort(function(a, b) { + if (a.toLowerCase() < b.toLowerCase()) return -1; + if (a.toLowerCase() > b.toLowerCase()) return 1; + return 0; + }); + + var deleteRange = new Range(0, 0, 0, 0); + for (var i = rows.first; i <= rows.last; i++) { + var line = session.getLine(i); + deleteRange.start.row = i; + deleteRange.end.row = i; + deleteRange.end.column = line.length; + session.replace(deleteRange, lines[i-rows.first]); + } + }; + + /** + * Editor.toggleCommentLines() + * + * Given the currently selected range, this function either comments all the lines, or uncomments all of them. + **/ + this.toggleCommentLines = function() { + var state = this.session.getState(this.getCursorPosition().row); + var rows = this.$getSelectedRows(); + this.session.getMode().toggleCommentLines(state, this.session, rows.first, rows.last); + }; + + /** + * Editor.getNumberAt() -> Number + * + * Works like [[Editor.getTokenAt]], except it returns a number. + **/ + this.getNumberAt = function( row, column ) { + var _numberRx = /[\-]?[0-9]+(?:\.[0-9]+)?/g + _numberRx.lastIndex = 0 + + var s = this.session.getLine(row) + while(_numberRx.lastIndex < column - 1 ){ + var m = _numberRx.exec(s) + if(m.index <= column && m.index+m[0].length >= column){ + var number = { + value: m[0], + start: m.index, + end: m.index+m[0].length + + } + return number + } + } + return null; + }; + /** + * Editor.modifyNumber(amount) + * - amount (Number): The value to change the numeral by (can be negative to decrease value) + * + * If the character before the cursor is a number, this functions changes its value by `amount`. + **/ + this.modifyNumber = function(amount) { + var row = this.selection.getCursor().row; + var column = this.selection.getCursor().column; + + // get the char before the cursor + var charRange = new Range(row, column-1, row, column); + + var c = this.session.getTextRange(charRange); + // if the char is a digit + if (!isNaN(parseFloat(c)) && isFinite(c)) { + // get the whole number the digit is part of + var nr = this.getNumberAt(row, column); + // if number found + if (nr) { + var fp = nr.value.indexOf(".") >= 0 ? nr.start + nr.value.indexOf(".") + 1 : nr.end; + var decimals = nr.start + nr.value.length - fp; + + var t = parseFloat(nr.value); + t *= Math.pow(10, decimals); + + + if(fp !== nr.end && column < fp){ + amount *= Math.pow(10, nr.end - column - 1); + } else { + amount *= Math.pow(10, nr.end - column); + } + + t += amount; + t /= Math.pow(10, decimals); + var nnr = t.toFixed(decimals); + + //update number + var replaceRange = new Range(row, nr.start, row, nr.end); + this.session.replace(replaceRange, nnr); + + //reposition the cursor + this.moveCursorTo(row, Math.max(nr.start +1, column + nnr.length - nr.value.length)); + + } + } + }; + + /** related to: EditSession.remove + * Editor.removeLines() + * + * Removes all the lines in the current selection + **/ + this.removeLines = function() { + var rows = this.$getSelectedRows(); + var range; + if (rows.first === 0 || rows.last+1 < this.session.getLength()) + range = new Range(rows.first, 0, rows.last+1, 0); + else + range = new Range( + rows.first-1, this.session.getLine(rows.first-1).length, + rows.last, this.session.getLine(rows.last).length + ); + this.session.remove(range); + this.clearSelection(); + }; + + this.duplicateSelection = function() { + var sel = this.selection; + var doc = this.session; + var range = sel.getRange(); + if (range.isEmpty()) { + var row = range.start.row; + doc.duplicateLines(row, row); + } else { + var reverse = sel.isBackwards() + var point = sel.isBackwards() ? range.start : range.end; + var endPoint = doc.insert(point, doc.getTextRange(range), false); + range.start = point; + range.end = endPoint; + + sel.setSelectionRange(range, reverse) + } + }; + + /** related to: EditSession.moveLinesDown + * Editor.moveLinesDown() -> Number + * + (Number): On success, it returns -1. + * + * Shifts all the selected lines down one row. + * + * + * + **/ + this.moveLinesDown = function() { + this.$moveLines(function(firstRow, lastRow) { + return this.session.moveLinesDown(firstRow, lastRow); + }); + }; + + /** related to: EditSession.moveLinesUp + * Editor.moveLinesUp() -> Number + * + (Number): On success, it returns -1. + * + * Shifts all the selected lines up one row. + * + * + **/ + this.moveLinesUp = function() { + this.$moveLines(function(firstRow, lastRow) { + return this.session.moveLinesUp(firstRow, lastRow); + }); + }; + + /** related to: EditSession.moveText + * Editor.moveText(fromRange, toPosition) -> Range + * - fromRange (Range): The range of text you want moved within the document + * - toPosition (Object): The location (row and column) where you want to move the text to + * + (Range): The new range where the text was moved to. + * + * Moves a range of text from the given range to the given position. `toPosition` is an object that looks like this: + * + * { row: newRowLocation, column: newColumnLocation } + * + * + **/ + this.moveText = function(range, toPosition) { + if (this.$readOnly) + return null; + + return this.session.moveText(range, toPosition); + }; + + /** related to: EditSession.duplicateLines + * Editor.copyLinesUp() -> Number + * + (Number): On success, returns 0. + * + * Copies all the selected lines up one row. + * + * + **/ + this.copyLinesUp = function() { + this.$moveLines(function(firstRow, lastRow) { + this.session.duplicateLines(firstRow, lastRow); + return 0; + }); + }; + + /** related to: EditSession.duplicateLines + * Editor.copyLinesDown() -> Number + * + (Number): On success, returns the number of new rows added; in other words, `lastRow - firstRow + 1`. + * + * Copies all the selected lines down one row. + * + * + * + **/ + this.copyLinesDown = function() { + this.$moveLines(function(firstRow, lastRow) { + return this.session.duplicateLines(firstRow, lastRow); + }); + }; + + + /** + * Editor.$moveLines(mover) + * - mover (Function): A method to call on each selected row + * + * Executes a specific function, which can be anything that manipulates selected lines, such as copying them, duplicating them, or shifting them. + * + **/ + this.$moveLines = function(mover) { + var rows = this.$getSelectedRows(); + var selection = this.selection; + if (!selection.isMultiLine()) { + var range = selection.getRange(); + var reverse = selection.isBackwards(); + } + + var linesMoved = mover.call(this, rows.first, rows.last); + + if (range) { + range.start.row += linesMoved; + range.end.row += linesMoved; + selection.setSelectionRange(range, reverse); + } + else { + selection.setSelectionAnchor(rows.last+linesMoved+1, 0); + selection.$moveSelection(function() { + selection.moveCursorTo(rows.first+linesMoved, 0); + }); + } + }; + + /** + * Editor.$getSelectedRows() -> Object + * + * Returns an object indicating the currently selected rows. The object looks like this: + * + * { first: range.start.row, last: range.end.row } + * + **/ + this.$getSelectedRows = function() { + var range = this.getSelectionRange().collapseRows(); + + return { + first: range.start.row, + last: range.end.row + }; + }; + + this.onCompositionStart = function(text) { + this.renderer.showComposition(this.getCursorPosition()); + }; + + this.onCompositionUpdate = function(text) { + this.renderer.setCompositionText(text); + }; + + this.onCompositionEnd = function() { + this.renderer.hideComposition(); + }; + + /** related to: VirtualRenderer.getFirstVisibleRow + * Editor.getFirstVisibleRow() -> Number + * + * {:VirtualRenderer.getFirstVisibleRow} + **/ + this.getFirstVisibleRow = function() { + return this.renderer.getFirstVisibleRow(); + }; + + /** related to: VirtualRenderer.getLastVisibleRow + * Editor.getLastVisibleRow() -> Number + * + * {:VirtualRenderer.getLastVisibleRow} + **/ + this.getLastVisibleRow = function() { + return this.renderer.getLastVisibleRow(); + }; + + /** + * Editor.isRowVisible(row) -> Boolean + * - row (Number): The row to check + * + * Indicates if the row is currently visible on the screen. + **/ + this.isRowVisible = function(row) { + return (row >= this.getFirstVisibleRow() && row <= this.getLastVisibleRow()); + }; + + /** + * Editor.isRowFullyVisible(row) -> Boolean + * - row (Number): The row to check + * + * Indicates if the entire row is currently visible on the screen. + **/ + this.isRowFullyVisible = function(row) { + return (row >= this.renderer.getFirstFullyVisibleRow() && row <= this.renderer.getLastFullyVisibleRow()); + }; + + /** + * Editor.$getVisibleRowCount() -> Number + * + * Returns the number of currently visibile rows. + **/ + this.$getVisibleRowCount = function() { + return this.renderer.getScrollBottomRow() - this.renderer.getScrollTopRow() + 1; + }; + + this.$moveByPage = function(dir, select) { + var renderer = this.renderer; + var config = this.renderer.layerConfig; + var rows = dir * Math.floor(config.height / config.lineHeight); + + this.$blockScrolling++; + if (select == true) { + this.selection.$moveSelection(function(){ + this.moveCursorBy(rows, 0); + }); + } else if (select == false) { + this.selection.moveCursorBy(rows, 0); + this.selection.clearSelection(); + } + this.$blockScrolling--; + + var scrollTop = renderer.scrollTop; + + renderer.scrollBy(0, rows * config.lineHeight); + if (select != null) + renderer.scrollCursorIntoView(null, 0.5); + + renderer.animateScrolling(scrollTop); + }; + + /** + * Editor.selectPageDown() + * + * Selects the text from the current position of the document until where a "page down" finishes. + **/ + this.selectPageDown = function() { + this.$moveByPage(1, true); + }; + + /** + * Editor.selectPageUp() + * + * Selects the text from the current position of the document until where a "page up" finishes. + **/ + this.selectPageUp = function() { + this.$moveByPage(-1, true); + }; + + /** + * Editor.gotoPageDown() + * + * Shifts the document to wherever "page down" is, as well as moving the cursor position. + **/ + this.gotoPageDown = function() { + this.$moveByPage(1, false); + }; + + /** + * Editor.gotoPageUp() + * + * Shifts the document to wherever "page up" is, as well as moving the cursor position. + **/ + this.gotoPageUp = function() { + this.$moveByPage(-1, false); + }; + + /** + * Editor.scrollPageDown() + * + * Scrolls the document to wherever "page down" is, without changing the cursor position. + **/ + this.scrollPageDown = function() { + this.$moveByPage(1); + }; + + /** + * Editor.scrollPageUp() + * + * Scrolls the document to wherever "page up" is, without changing the cursor position. + **/ + this.scrollPageUp = function() { + this.$moveByPage(-1); + }; + + /** related to: VirtualRenderer.scrollToRow + * Editor.scrollToRow(row) + * - row (Number): The row to move to + * + * Moves the editor to the specified row. + * + **/ + this.scrollToRow = function(row) { + this.renderer.scrollToRow(row); + }; + + /** related to: VirtualRenderer.scrollToLine + * Editor.scrollToLine(line, center, animate, callback()) + * - line (Number): The line to scroll to + * - center (Boolean): If `true` + * - animate (Boolean): If `true` animates scrolling + * - callback (Function): Function to be called when the animation has finished + * + * TODO scrolls a to line, if center == true, puts line in middle of screen or attempts to) + **/ + this.scrollToLine = function(line, center, animate, callback) { + this.renderer.scrollToLine(line, center, animate, callback); + }; + + /** + * Editor.centerSelection() + * + * Attempts to center the current selection on the screen. + **/ + this.centerSelection = function() { + var range = this.getSelectionRange(); + var pos = { + row: Math.floor(range.start.row + (range.end.row - range.start.row) / 2), + column: Math.floor(range.start.column + (range.end.column - range.start.column) / 2) + } + this.renderer.alignCursor(pos, 0.5); + }; + + /** related to: Selection.getCursor + * Editor.getCursorPosition() -> Object + * + (Object): This returns an object that looks something like this:
+ * ```{ row: currRow, column: currCol }``` + * + * Gets the current position of the cursor. + * + * + * + **/ + this.getCursorPosition = function() { + return this.selection.getCursor(); + }; + + /** related to: EditSession.documentToScreenPosition + * Editor.getCursorPositionScreen() -> Number + * + * Returns the screen position of the cursor. + **/ + this.getCursorPositionScreen = function() { + return this.session.documentToScreenPosition(this.getCursorPosition()); + }; + + /** related to: Selection.getRange + * Editor.getSelectionRange() -> Range + * + * {:Selection.getRange} + **/ + this.getSelectionRange = function() { + return this.selection.getRange(); + }; + + + /** related to: Selection.selectAll + * Editor.selectAll() + * + * Selects all the text in editor. + **/ + this.selectAll = function() { + this.$blockScrolling += 1; + this.selection.selectAll(); + this.$blockScrolling -= 1; + }; + + /** related to: Selection.clearSelection + * Editor.clearSelection() + * + * {:Selection.clearSelection} + **/ + this.clearSelection = function() { + this.selection.clearSelection(); + }; + + /** related to: Selection.moveCursorTo + * Editor.moveCursorTo(row, column) + * - row (Number): The new row number + * - column (Number): The new column number + * + * Moves the cursor to the specified row and column. Note that this does not de-select the current selection. + * + **/ + this.moveCursorTo = function(row, column) { + this.selection.moveCursorTo(row, column); + }; + + /** related to: Selection.moveCursorToPosition + * Editor.moveCursorToPosition(pos) + * - pos (Object): An object with two properties, row and column + * + * Moves the cursor to the position indicated by `pos.row` and `pos.column`. + * + **/ + this.moveCursorToPosition = function(pos) { + this.selection.moveCursorToPosition(pos); + }; + + /** + * Editor.jumpToMatching() + * + * Moves the cursor's row and column to the next matching bracket. + * + **/ + this.jumpToMatching = function(select) { + var cursor = this.getCursorPosition(); + + var range = this.session.getBracketRange(cursor); + if (!range) { + range = this.find({ + needle: /[{}()\[\]]/g, + preventScroll:true, + start: {row: cursor.row, column: cursor.column - 1} + }); + if (!range) + return; + var pos = range.start; + if (pos.row == cursor.row && Math.abs(pos.column - cursor.column) < 2) + range = this.session.getBracketRange(pos); + } + + pos = range && range.cursor || pos; + if (pos) { + if (select) { + if (range && range.isEqual(this.getSelectionRange())) + this.clearSelection(); + else + this.selection.selectTo(pos.row, pos.column); + } else { + this.clearSelection(); + this.moveCursorTo(pos.row, pos.column); + } + } + }; + + /** + * Editor.gotoLine(lineNumber, column, animate) + * - lineNumber (Number): The line number to go to + * - column (Number): A column number to go to + * - animate (Boolean): If `true` animates scolling + * + * Moves the cursor to the specified line number, and also into the indiciated column. + * + **/ + this.gotoLine = function(lineNumber, column, animate) { + this.selection.clearSelection(); + this.session.unfold({row: lineNumber - 1, column: column || 0}); + + this.$blockScrolling += 1; + this.moveCursorTo(lineNumber - 1, column || 0); + this.$blockScrolling -= 1; + + if (!this.isRowFullyVisible(lineNumber - 1)) + this.scrollToLine(lineNumber - 1, true, animate); + }; + + /** related to: Editor.moveCursorTo + * Editor.navigateTo(row, column) + * - row (Number): The new row number + * - column (Number): The new column number + * + * Moves the cursor to the specified row and column. Note that this does de-select the current selection. + * + **/ + this.navigateTo = function(row, column) { + this.clearSelection(); + this.moveCursorTo(row, column); + }; + + /** + * Editor.navigateUp(times) + * - times (Number): The number of times to change navigation + * + * Moves the cursor up in the document the specified number of times. Note that this does de-select the current selection. + **/ + this.navigateUp = function(times) { + this.selection.clearSelection(); + times = times || 1; + this.selection.moveCursorBy(-times, 0); + }; + + /** + * Editor.navigateDown(times) + * - times (Number): The number of times to change navigation + * + * Moves the cursor down in the document the specified number of times. Note that this does de-select the current selection. + **/ + this.navigateDown = function(times) { + this.selection.clearSelection(); + times = times || 1; + this.selection.moveCursorBy(times, 0); + }; + + /** + * Editor.navigateLeft(times) + * - times (Number): The number of times to change navigation + * + * Moves the cursor left in the document the specified number of times. Note that this does de-select the current selection. + **/ + this.navigateLeft = function(times) { + if (!this.selection.isEmpty()) { + var selectionStart = this.getSelectionRange().start; + this.moveCursorToPosition(selectionStart); + } + else { + times = times || 1; + while (times--) { + this.selection.moveCursorLeft(); + } + } + this.clearSelection(); + }; + + /** + * Editor.navigateRight(times) + * - times (Number): The number of times to change navigation + * + * Moves the cursor right in the document the specified number of times. Note that this does de-select the current selection. + **/ + this.navigateRight = function(times) { + if (!this.selection.isEmpty()) { + var selectionEnd = this.getSelectionRange().end; + this.moveCursorToPosition(selectionEnd); + } + else { + times = times || 1; + while (times--) { + this.selection.moveCursorRight(); + } + } + this.clearSelection(); + }; + + /** + * Editor.navigateLineStart() + * + * Moves the cursor to the start of the current line. Note that this does de-select the current selection. + **/ + this.navigateLineStart = function() { + this.selection.moveCursorLineStart(); + this.clearSelection(); + }; + + /** + * Editor.navigateLineEnd() + * + * Moves the cursor to the end of the current line. Note that this does de-select the current selection. + **/ + this.navigateLineEnd = function() { + this.selection.moveCursorLineEnd(); + this.clearSelection(); + }; + + /** + * Editor.navigateFileEnd() + * + * Moves the cursor to the end of the current file. Note that this does de-select the current selection. + **/ + this.navigateFileEnd = function() { + var scrollTop = this.renderer.scrollTop; + this.selection.moveCursorFileEnd(); + this.clearSelection(); + this.renderer.animateScrolling(scrollTop); + }; + + /** + * Editor.navigateFileStart() + * + * Moves the cursor to the start of the current file. Note that this does de-select the current selection. + **/ + this.navigateFileStart = function() { + var scrollTop = this.renderer.scrollTop; + this.selection.moveCursorFileStart(); + this.clearSelection(); + this.renderer.animateScrolling(scrollTop); + }; + + /** + * Editor.navigateWordRight() + * + * Moves the cursor to the word immediately to the right of the current position. Note that this does de-select the current selection. + **/ + this.navigateWordRight = function() { + this.selection.moveCursorWordRight(); + this.clearSelection(); + }; + + /** + * Editor.navigateWordLeft() + * + * Moves the cursor to the word immediately to the left of the current position. Note that this does de-select the current selection. + **/ + this.navigateWordLeft = function() { + this.selection.moveCursorWordLeft(); + this.clearSelection(); + }; + + /** + * Editor.replace(replacement, options) + * - replacement (String): The text to replace with + * - options (Object): The [[Search `Search`]] options to use + * + * Replaces the first occurance of `options.needle` with the value in `replacement`. + **/ + this.replace = function(replacement, options) { + if (options) + this.$search.set(options); + + var range = this.$search.find(this.session); + var replaced = 0; + if (!range) + return replaced; + + if (this.$tryReplace(range, replacement)) { + replaced = 1; + } + if (range !== null) { + this.selection.setSelectionRange(range); + this.renderer.scrollSelectionIntoView(range.start, range.end); + } + + return replaced; + }; + + /** + * Editor.replaceAll(replacement, options) + * - replacement (String): The text to replace with + * - options (Object): The [[Search `Search`]] options to use + * + * Replaces all occurances of `options.needle` with the value in `replacement`. + **/ + this.replaceAll = function(replacement, options) { + if (options) { + this.$search.set(options); + } + + var ranges = this.$search.findAll(this.session); + var replaced = 0; + if (!ranges.length) + return replaced; + + this.$blockScrolling += 1; + + var selection = this.getSelectionRange(); + this.clearSelection(); + this.selection.moveCursorTo(0, 0); + + for (var i = ranges.length - 1; i >= 0; --i) { + if(this.$tryReplace(ranges[i], replacement)) { + replaced++; + } + } + + this.selection.setSelectionRange(selection); + this.$blockScrolling -= 1; + + return replaced; + }; + + this.$tryReplace = function(range, replacement) { + var input = this.session.getTextRange(range); + replacement = this.$search.replace(input, replacement); + if (replacement !== null) { + range.end = this.session.replace(range, replacement); + return range; + } else { + return null; + } + }; + + /** related to: Search.getOptions + * Editor.getLastSearchOptions() -> Object + * + * {:Search.getOptions} For more information on `options`, see [[Search `Search`]]. + **/ + this.getLastSearchOptions = function() { + return this.$search.getOptions(); + }; + + /** related to: Search.find + * Editor.find(needle, options, animate) + * - needle (String): The text to search for (optional) + * - options (Object): An object defining various search properties + * - animate (Boolean): If `true` animate scrolling + * + * Attempts to find `needle` within the document. For more information on `options`, see [[Search `Search`]]. + **/ + this.find = function(needle, options, animate) { + if (!options) + options = {}; + + if (typeof needle == "string" || needle instanceof RegExp) + options.needle = needle; + else if (typeof needle == "object") + oop.mixin(options, needle); + + var range = this.selection.getRange(); + if (options.needle == null) { + needle = this.session.getTextRange(range) + || this.$search.$options.needle; + if (!needle) { + range = this.session.getWordRange(range.start.row, range.start.column); + needle = this.session.getTextRange(range); + } + this.$search.set({needle: needle}); + } + + this.$search.set(options); + if (!options.start) + this.$search.set({start: range}); + + var newRange = this.$search.find(this.session); + if (options.preventScroll) + return newRange; + if (newRange) { + this.revealRange(newRange, animate); + return newRange; + } + // clear selection if nothing is found + if (options.backwards) + range.start = range.end; + else + range.end = range.start; + this.selection.setRange(range); + }; + + /** related to: Editor.find + * Editor.findNext(options, animate) + * - options (Object): search options + * - animate (Boolean): If `true` animate scrolling + * + * Performs another search for `needle` in the document. For more information on `options`, see [[Search `Search`]]. + **/ + this.findNext = function(options, animate) { + this.find({skipCurrent: true, backwards: false}, options, animate); + }; + + /** related to: Editor.find + * Editor.findPrevious(options, animate) + * - options (Object): search options + * - animate (Boolean): If `true` animate scrolling + * + * Performs a search for `needle` backwards. For more information on `options`, see [[Search `Search`]]. + **/ + this.findPrevious = function(options, animate) { + this.find(options, {skipCurrent: true, backwards: true}, animate); + }; + + this.revealRange = function(range, animate) { + this.$blockScrolling += 1; + this.session.unfold(range); + this.selection.setSelectionRange(range); + this.$blockScrolling -= 1; + + var scrollTop = this.renderer.scrollTop; + this.renderer.scrollSelectionIntoView(range.start, range.end, 0.5); + if (animate != false) + this.renderer.animateScrolling(scrollTop); + }; + + /** related to: UndoManager.undo + * Editor.undo() + * + * {:UndoManager.undo} + **/ + this.undo = function() { + this.$blockScrolling++; + this.session.getUndoManager().undo(); + this.$blockScrolling--; + this.renderer.scrollCursorIntoView(null, 0.5); + }; + + /** related to: UndoManager.redo + * Editor.redo() + * + * {:UndoManager.redo} + **/ + this.redo = function() { + this.$blockScrolling++; + this.session.getUndoManager().redo(); + this.$blockScrolling--; + this.renderer.scrollCursorIntoView(null, 0.5); + }; + + /** + * Editor.destroy() + * + * Cleans up the entire editor. + **/ + this.destroy = function() { + this.renderer.destroy(); + }; + +}).call(Editor.prototype); + + +exports.Editor = Editor; +}); diff --git a/lib/ace/editor_change_document_test.js b/lib/ace/editor_change_document_test.js new file mode 100644 index 0000000000..a1fdaad9d4 --- /dev/null +++ b/lib/ace/editor_change_document_test.js @@ -0,0 +1,188 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); + require("./test/mockdom"); +} + +define(function(require, exports, module) { +"use strict"; + +var EditSession = require("./edit_session").EditSession; +var Editor = require("./editor").Editor; +var Text = require("./mode/text").Mode; +var JavaScriptMode = require("./mode/javascript").Mode; +var CssMode = require("./mode/css").Mode; +var HtmlMode = require("./mode/html").Mode; +var MockRenderer = require("./test/mockrenderer").MockRenderer; +var assert = require("./test/assertions"); + +module.exports = { + + setUp : function(next) { + this.session1 = new EditSession(["abc", "def"]); + this.session2 = new EditSession(["ghi", "jkl"]); + + + this.editor = new Editor(new MockRenderer()); + next(); + }, + + "test: change document" : function() { + this.editor.setSession(this.session1); + assert.equal(this.editor.getSession(), this.session1); + + this.editor.setSession(this.session2); + assert.equal(this.editor.getSession(), this.session2); + }, + + "test: only changes to the new document should have effect" : function() { + var called = false; + this.editor.onDocumentChange = function() { + called = true; + }; + + this.editor.setSession(this.session1); + this.editor.setSession(this.session2); + + this.session1.duplicateLines(0, 0); + assert.notOk(called); + + this.session2.duplicateLines(0, 0); + assert.ok(called); + }, + + "test: should use cursor of new document" : function() { + this.session1.getSelection().moveCursorTo(0, 1); + this.session2.getSelection().moveCursorTo(1, 0); + + this.editor.setSession(this.session1); + assert.position(this.editor.getCursorPosition(), 0, 1); + + this.editor.setSession(this.session2); + assert.position(this.editor.getCursorPosition(), 1, 0); + }, + + "test: only changing the cursor of the new doc should not have an effect" : function() { + this.editor.onCursorChange = function() { + called = true; + }; + + this.editor.setSession(this.session1); + this.editor.setSession(this.session2); + assert.position(this.editor.getCursorPosition(), 0, 0); + + var called = false; + this.session1.getSelection().moveCursorTo(0, 1); + assert.position(this.editor.getCursorPosition(), 0, 0); + assert.notOk(called); + + this.session2.getSelection().moveCursorTo(1, 1); + assert.position(this.editor.getCursorPosition(), 1, 1); + assert.ok(called); + }, + + "test: should use selection of new document" : function() { + this.session1.getSelection().selectTo(0, 1); + this.session2.getSelection().selectTo(1, 0); + + this.editor.setSession(this.session1); + assert.position(this.editor.getSelection().getSelectionLead(), 0, 1); + + this.editor.setSession(this.session2); + assert.position(this.editor.getSelection().getSelectionLead(), 1, 0); + }, + + "test: only changing the selection of the new doc should not have an effect" : function() { + this.editor.onSelectionChange = function() { + called = true; + }; + + this.editor.setSession(this.session1); + this.editor.setSession(this.session2); + assert.position(this.editor.getSelection().getSelectionLead(), 0, 0); + + var called = false; + this.session1.getSelection().selectTo(0, 1); + assert.position(this.editor.getSelection().getSelectionLead(), 0, 0); + assert.notOk(called); + + this.session2.getSelection().selectTo(1, 1); + assert.position(this.editor.getSelection().getSelectionLead(), 1, 1); + assert.ok(called); + }, + + "test: should use mode of new document" : function() { + this.editor.onChangeMode = function() { + called = true; + }; + this.editor.setSession(this.session1); + this.editor.setSession(this.session2); + + var called = false; + this.session1.setMode(new Text()); + assert.notOk(called); + + this.session2.setMode(new JavaScriptMode()); + assert.ok(called); + }, + + "test: should use stop worker of old document" : function(next) { + var self = this; + + // 1. Open an editor and set the session to CssMode + self.editor.setSession(self.session1); + self.session1.setMode(new CssMode()); + + // 2. Add a line or two of valid CSS. + self.session1.setValue("DIV { color: red; }"); + + // 3. Clear the session value. + self.session1.setValue(""); + + // 4. Set the session to HtmlMode + self.session1.setMode(new HtmlMode()); + + // 5. Try to type valid HTML + self.session1.insert({row: 0, column: 0}, ""); + + setTimeout(function() { + assert.equal(Object.keys(self.session1.getAnnotations()).length, 0); + next(); + }, 600); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec() +} diff --git a/lib/ace/editor_highlight_selected_word_test.js b/lib/ace/editor_highlight_selected_word_test.js new file mode 100644 index 0000000000..864de9a175 --- /dev/null +++ b/lib/ace/editor_highlight_selected_word_test.js @@ -0,0 +1,223 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); + require("./test/mockdom"); +} + +define(function(require, exports, module) { +"use strict"; + +var EditSession = require("./edit_session").EditSession; +var Editor = require("./editor").Editor; +var MockRenderer = require("./test/mockrenderer").MockRenderer; +var assert = require("./test/assertions"); + +var lipsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " + + "Mauris at arcu mi, eu lobortis mauris. Quisque ut libero eget " + + "diam congue vehicula. Quisque ut odio ut mi aliquam tincidunt. " + + "Duis lacinia aliquam lorem eget eleifend. Morbi eget felis mi. " + + "Duis quam ligula, consequat vitae convallis volutpat, blandit " + + "nec neque. Nulla facilisi. Etiam suscipit lorem ac justo " + + "sollicitudin tristique. Phasellus ut posuere nunc. Aliquam " + + "scelerisque mollis felis non gravida. Vestibulum lacus sem, " + + "posuere non bibendum id, luctus non dolor. Aenean id metus " + + "lorem, vel dapibus est. Donec gravida feugiat augue nec " + + "accumsan.Lorem ipsum dolor sit amet, consectetur adipiscing " + + "elit. Nulla vulputate, velit vitae tincidunt congue, nunc " + + "augue accumsan velit, eu consequat turpis lectus ac orci. " + + "Pellentesque ornare dolor feugiat dui auctor eu varius nulla " + + "fermentum. Sed aliquam odio at velit lacinia vel fermentum " + + "felis sodales. In dignissim magna eget nunc lobortis non " + + "fringilla nibh ullamcorper. Donec facilisis malesuada elit " + + "at egestas. Etiam bibendum, diam vitae tempor aliquet, dui " + + "libero vehicula odio, eget bibendum mauris velit eu lorem.\n" + + "consectetur"; + +function callHighlighterUpdate(session, firstRow, lastRow) { + var rangeCount = 0; + var mockMarkerLayer = { drawSingleLineMarker: function() {rangeCount++;} } + session.$searchHighlight.update([], mockMarkerLayer, session, { + firstRow: firstRow, + lastRow: lastRow + }); + return rangeCount; +} + +module.exports = { + setUp: function(next) { + this.session = new EditSession(lipsum); + this.editor = new Editor(new MockRenderer(), this.session); + this.selection = this.session.getSelection(); + this.search = this.editor.$search; + next(); + }, + + "test: highlight selected words by default": function() { + assert.equal(this.editor.getHighlightSelectedWord(), true); + }, + + "test: highlight a word": function() { + this.editor.moveCursorTo(0, 9); + this.selection.selectWord(); + + var highlighter = this.editor.session.$searchHighlight; + assert.ok(highlighter != null); + + var range = this.selection.getRange(); + assert.equal(this.session.getTextRange(range), "ipsum"); + assert.equal(highlighter.cache.length, 0); + assert.equal(callHighlighterUpdate(this.session, 0, 0), 2); + }, + + "test: highlight a word and clear highlight": function() { + this.editor.moveCursorTo(0, 8); + this.selection.selectWord(); + + var range = this.selection.getRange(); + assert.equal(this.session.getTextRange(range), "ipsum"); + assert.equal(callHighlighterUpdate(this.session, 0, 0), 2); + + this.session.highlight(""); + assert.equal(this.session.$searchHighlight.cache.length, 0); + assert.equal(callHighlighterUpdate(this.session, 0, 0), 0); + }, + + "test: highlight another word": function() { + this.selection.moveCursorTo(0, 14); + this.selection.selectWord(); + + var range = this.selection.getRange(); + assert.equal(this.session.getTextRange(range), "dolor"); + assert.equal(callHighlighterUpdate(this.session, 0, 0), 4); + }, + + "test: no selection, no highlight": function() { + this.selection.clearSelection(); + assert.equal(callHighlighterUpdate(this.session, 0, 0), 0); + }, + + "test: select a word, no highlight": function() { + this.selection.moveCursorTo(0, 14); + this.selection.selectWord(); + + this.editor.setHighlightSelectedWord(false); + + var range = this.selection.getRange(); + assert.equal(this.session.getTextRange(range), "dolor"); + assert.equal(callHighlighterUpdate(this.session, 0, 0), 0); + }, + + "test: select a word with no matches": function() { + this.editor.setHighlightSelectedWord(true); + + var currentOptions = this.search.getOptions(); + var newOptions = { + wrap: true, + wholeWord: true, + caseSensitive: true, + needle: "Mauris" + }; + this.search.set(newOptions); + + var match = this.search.find(this.session); + assert.notEqual(match, null, "found a match for 'Mauris'"); + + this.search.set(currentOptions); + + this.selection.setSelectionRange(match); + + assert.equal(this.session.getTextRange(match), "Mauris"); + assert.equal(callHighlighterUpdate(this.session, 0, 0), 1); + }, + + "test: partial word selection 1": function() { + this.selection.moveCursorTo(0, 14); + this.selection.selectWord(); + this.selection.selectLeft(); + + var range = this.selection.getRange(); + assert.equal(this.session.getTextRange(range), "dolo"); + assert.equal(callHighlighterUpdate(this.session, 0, 0), 0); + }, + + "test: partial word selection 2": function() { + this.selection.moveCursorTo(0, 13); + this.selection.selectWord(); + this.selection.selectRight(); + + var range = this.selection.getRange(); + assert.equal(this.session.getTextRange(range), "dolor "); + assert.equal(callHighlighterUpdate(this.session, 0, 0), 0); + }, + + "test: partial word selection 3": function() { + this.selection.moveCursorTo(0, 14); + this.selection.selectWord(); + this.selection.selectLeft(); + this.selection.shiftSelection(1); + + var range = this.selection.getRange(); + assert.equal(this.session.getTextRange(range), "olor"); + assert.equal(callHighlighterUpdate(this.session, 0, 0), 0); + }, + + "test: select last word": function() { + this.selection.moveCursorTo(0, 1); + + var currentOptions = this.search.getOptions(); + var newOptions = { + wrap: true, + wholeWord: true, + caseSensitive: true, + backwards: true, + needle: "consectetur" + }; + this.search.set(newOptions); + + var match = this.search.find(this.session); + assert.notEqual(match, null, "found a match for 'consectetur'"); + assert.position(match.start, 1, 0); + + this.search.set(currentOptions); + + this.selection.setSelectionRange(match); + + assert.equal(this.session.getTextRange(match), "consectetur"); + assert.equal(callHighlighterUpdate(this.session, 0, 1), 3); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/lib/ace/editor_navigation_test.js b/lib/ace/editor_navigation_test.js new file mode 100644 index 0000000000..ab348241b4 --- /dev/null +++ b/lib/ace/editor_navigation_test.js @@ -0,0 +1,164 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); + require("./test/mockdom"); +} + +define(function(require, exports, module) { +"use strict"; + +var EditSession = require("./edit_session").EditSession; +var Editor = require("./editor").Editor; +var MockRenderer = require("./test/mockrenderer").MockRenderer; +var assert = require("./test/assertions"); + +module.exports = { + createEditSession : function(rows, cols) { + var line = new Array(cols + 1).join("a"); + var text = new Array(rows).join(line + "\n") + line; + return new EditSession(text); + }, + + "test: navigate to end of file should scroll the last line into view" : function() { + var doc = this.createEditSession(200, 10); + var editor = new Editor(new MockRenderer(), doc); + + editor.navigateFileEnd(); + var cursor = editor.getCursorPosition(); + + assert.ok(editor.getFirstVisibleRow() <= cursor.row); + assert.ok(editor.getLastVisibleRow() >= cursor.row); + }, + + "test: navigate to start of file should scroll the first row into view" : function() { + var doc = this.createEditSession(200, 10); + var editor = new Editor(new MockRenderer(), doc); + + editor.moveCursorTo(editor.getLastVisibleRow() + 20); + editor.navigateFileStart(); + + assert.equal(editor.getFirstVisibleRow(), 0); + }, + + "test: goto hidden line should scroll the line into the middle of the viewport" : function() { + var editor = new Editor(new MockRenderer(), this.createEditSession(200, 5)); + + editor.navigateTo(0, 0); + editor.gotoLine(101); + assert.position(editor.getCursorPosition(), 100, 0); + assert.equal(editor.getFirstVisibleRow(), 89); + + editor.navigateTo(100, 0); + editor.gotoLine(11); + assert.position(editor.getCursorPosition(), 10, 0); + assert.equal(editor.getFirstVisibleRow(), 0); + + editor.navigateTo(100, 0); + editor.gotoLine(6); + assert.position(editor.getCursorPosition(), 5, 0); + assert.equal(0, editor.getFirstVisibleRow(), 0); + + editor.navigateTo(100, 0); + editor.gotoLine(1); + assert.position(editor.getCursorPosition(), 0, 0); + assert.equal(editor.getFirstVisibleRow(), 0); + + editor.navigateTo(0, 0); + editor.gotoLine(191); + assert.position(editor.getCursorPosition(), 190, 0); + assert.equal(editor.getFirstVisibleRow(), 179); + + editor.navigateTo(0, 0); + editor.gotoLine(196); + assert.position(editor.getCursorPosition(), 195, 0); + assert.equal(editor.getFirstVisibleRow(), 180); + }, + + "test: goto visible line should only move the cursor and not scroll": function() { + var editor = new Editor(new MockRenderer(), this.createEditSession(200, 5)); + + editor.navigateTo(0, 0); + editor.gotoLine(12); + assert.position(editor.getCursorPosition(), 11, 0); + assert.equal(editor.getFirstVisibleRow(), 0); + + editor.navigateTo(30, 0); + editor.gotoLine(33); + assert.position(editor.getCursorPosition(), 32, 0); + assert.equal(editor.getFirstVisibleRow(), 30); + }, + + "test: navigate from the end of a long line down to a short line and back should maintain the curser column": function() { + var editor = new Editor(new MockRenderer(), new EditSession(["123456", "1"])); + + editor.navigateTo(0, 6); + assert.position(editor.getCursorPosition(), 0, 6); + + editor.navigateDown(); + assert.position(editor.getCursorPosition(), 1, 1); + + editor.navigateUp(); + assert.position(editor.getCursorPosition(), 0, 6); + }, + + "test: reset desired column on navigate left or right": function() { + var editor = new Editor(new MockRenderer(), new EditSession(["123456", "12"])); + + editor.navigateTo(0, 6); + assert.position(editor.getCursorPosition(), 0, 6); + + editor.navigateDown(); + assert.position(editor.getCursorPosition(), 1, 2); + + editor.navigateLeft(); + assert.position(editor.getCursorPosition(), 1, 1); + + editor.navigateUp(); + assert.position(editor.getCursorPosition(), 0, 1); + }, + + "test: typing text should update the desired column": function() { + var editor = new Editor(new MockRenderer(), new EditSession(["1234", "1234567890"])); + + editor.navigateTo(0, 3); + editor.insert("juhu"); + + editor.navigateDown(); + assert.position(editor.getCursorPosition(), 1, 7); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec() +} diff --git a/lib/ace/editor_text_edit_test.js b/lib/ace/editor_text_edit_test.js new file mode 100644 index 0000000000..cda1e4264d --- /dev/null +++ b/lib/ace/editor_text_edit_test.js @@ -0,0 +1,555 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); + require("./test/mockdom"); +} + +define(function(require, exports, module) { +"use strict"; + +var EditSession = require("./edit_session").EditSession; +var Editor = require("./editor").Editor; +var JavaScriptMode = require("./mode/javascript").Mode; +var UndoManager = require("./undomanager").UndoManager; +var MockRenderer = require("./test/mockrenderer").MockRenderer; +var assert = require("./test/assertions"); + +module.exports = { + "test: delete line from the middle" : function() { + var session = new EditSession(["a", "b", "c", "d"].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 1); + editor.removeLines(); + + assert.equal(session.toString(), "a\nc\nd"); + assert.position(editor.getCursorPosition(), 1, 0); + + editor.removeLines(); + + assert.equal(session.toString(), "a\nd"); + assert.position(editor.getCursorPosition(), 1, 0); + + editor.removeLines(); + + assert.equal(session.toString(), "a"); + assert.position(editor.getCursorPosition(), 0, 1); + + editor.removeLines(); + + assert.equal(session.toString(), ""); + assert.position(editor.getCursorPosition(), 0, 0); + }, + + "test: delete multiple selected lines" : function() { + var session = new EditSession(["a", "b", "c", "d"].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 1); + editor.getSelection().selectDown(); + + editor.removeLines(); + assert.equal(session.toString(), "a\nd"); + assert.position(editor.getCursorPosition(), 1, 0); + }, + + "test: delete first line" : function() { + var session = new EditSession(["a", "b", "c"].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.removeLines(); + + assert.equal(session.toString(), "b\nc"); + assert.position(editor.getCursorPosition(), 0, 0); + }, + + "test: delete last should also delete the new line of the previous line" : function() { + var session = new EditSession(["a", "b", "c", ""].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(3, 0); + + editor.removeLines(); + assert.equal(session.toString(), "a\nb\nc"); + assert.position(editor.getCursorPosition(), 2, 1); + + editor.removeLines(); + assert.equal(session.toString(), "a\nb"); + assert.position(editor.getCursorPosition(), 1, 1); + }, + + "test: indent block" : function() { + var session = new EditSession(["a12345", "b12345", "c12345"].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 3); + editor.getSelection().selectDown(); + + editor.indent(); + + assert.equal(["a12345", " b12345", " c12345"].join("\n"), session.toString()); + + assert.position(editor.getCursorPosition(), 2, 7); + + var range = editor.getSelectionRange(); + assert.position(range.start, 1, 7); + assert.position(range.end, 2, 7); + }, + + "test: indent selected lines" : function() { + var session = new EditSession(["a12345", "b12345", "c12345"].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 0); + editor.getSelection().selectDown(); + + editor.indent(); + assert.equal(["a12345", " b12345", "c12345"].join("\n"), session.toString()); + }, + + "test: no auto indent if cursor is before the {" : function() { + var session = new EditSession("{", new JavaScriptMode()); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 0); + editor.onTextInput("\n"); + assert.equal(["", "{"].join("\n"), session.toString()); + }, + + "test: outdent block" : function() { + var session = new EditSession([" a12345", " b12345", " c12345"].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 5); + editor.getSelection().selectDown(); + editor.getSelection().selectDown(); + + editor.blockOutdent(); + assert.equal(session.toString(), [" a12345", "b12345", " c12345"].join("\n")); + + assert.position(editor.getCursorPosition(), 2, 1); + + var range = editor.getSelectionRange(); + assert.position(range.start, 0, 1); + assert.position(range.end, 2, 1); + + editor.blockOutdent(); + assert.equal(session.toString(), ["a12345", "b12345", "c12345"].join("\n")); + + var range = editor.getSelectionRange(); + assert.position(range.start, 0, 0); + assert.position(range.end, 2, 0); + }, + + "test: outent without a selection should update cursor" : function() { + var session = new EditSession(" 12"); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 3); + editor.blockOutdent(" "); + + assert.equal(session.toString(), " 12"); + assert.position(editor.getCursorPosition(), 0, 0); + }, + + "test: comment lines should perserve selection" : function() { + var session = new EditSession([" abc", "cde"].join("\n"), new JavaScriptMode()); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 2); + editor.getSelection().selectDown(); + editor.toggleCommentLines(); + + assert.equal(["// abc", "//cde"].join("\n"), session.toString()); + + var selection = editor.getSelectionRange(); + assert.position(selection.start, 0, 4); + assert.position(selection.end, 1, 4); + }, + + "test: uncomment lines should perserve selection" : function() { + var session = new EditSession(["// abc", "//cde"].join("\n"), new JavaScriptMode()); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 1); + editor.getSelection().selectDown(); + editor.getSelection().selectRight(); + editor.getSelection().selectRight(); + + editor.toggleCommentLines(); + + assert.equal([" abc", "cde"].join("\n"), session.toString()); + assert.range(editor.getSelectionRange(), 0, 0, 1, 1); + }, + + "test: toggle comment lines twice should return the original text" : function() { + var session = new EditSession([" abc", "cde", "fg"], new JavaScriptMode()); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 0); + editor.getSelection().selectDown(); + editor.getSelection().selectDown(); + + editor.toggleCommentLines(); + editor.toggleCommentLines(); + + assert.equal([" abc", "cde", "fg"].join("\n"), session.toString()); + }, + + + "test: comment lines - if the selection end is at the line start it should stay there": function() { + //select down + var session = new EditSession(["abc", "cde"].join("\n"), new JavaScriptMode()); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 0); + editor.getSelection().selectDown(); + + editor.toggleCommentLines(); + assert.range(editor.getSelectionRange(), 0, 2, 1, 0); + + // select up + var session = new EditSession(["abc", "cde"].join("\n"), new JavaScriptMode()); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 0); + editor.getSelection().selectUp(); + + editor.toggleCommentLines(); + assert.range(editor.getSelectionRange(), 0, 2, 1, 0); + }, + + "test: move lines down should select moved lines" : function() { + var session = new EditSession(["11", "22", "33", "44"].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 1); + editor.getSelection().selectDown(); + + editor.moveLinesDown(); + assert.equal(["33", "11", "22", "44"].join("\n"), session.toString()); + assert.position(editor.getCursorPosition(), 1, 0); + assert.position(editor.getSelection().getSelectionAnchor(), 3, 0); + assert.position(editor.getSelection().getSelectionLead(), 1, 0); + + editor.moveLinesDown(); + assert.equal(["33", "44", "11", "22"].join("\n"), session.toString()); + assert.position(editor.getCursorPosition(), 2, 0); + assert.position(editor.getSelection().getSelectionAnchor(), 3, 2); + assert.position(editor.getSelection().getSelectionLead(), 2, 0); + + // moving again should have no effect + editor.moveLinesDown(); + assert.equal(["33", "44", "11", "22"].join("\n"), session.toString()); + assert.position(editor.getCursorPosition(), 2, 0); + assert.position(editor.getSelection().getSelectionAnchor(), 3, 2); + assert.position(editor.getSelection().getSelectionLead(), 2, 0); + }, + + "test: move lines up should select moved lines" : function() { + var session = new EditSession(["11", "22", "33", "44"].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(2, 1); + editor.getSelection().selectDown(); + + editor.moveLinesUp(); + assert.equal(session.toString(), ["11", "33", "44", "22"].join("\n")); + assert.position(editor.getCursorPosition(), 1, 0); + assert.position(editor.getSelection().getSelectionAnchor(), 3, 0); + assert.position(editor.getSelection().getSelectionLead(), 1, 0); + + editor.moveLinesUp(); + assert.equal(session.toString(), ["33", "44", "11", "22"].join("\n")); + assert.position(editor.getCursorPosition(), 0, 0); + assert.position(editor.getSelection().getSelectionAnchor(), 2, 0); + assert.position(editor.getSelection().getSelectionLead(), 0, 0); + }, + + "test: move line without active selection should not move cursor relative to the moved line" : function() + { + var session = new EditSession(["11", "22", "33", "44"].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 1); + editor.clearSelection(); + + editor.moveLinesDown(); + assert.equal(["11", "33", "22", "44"].join("\n"), session.toString()); + assert.position(editor.getCursorPosition(), 2, 1); + + editor.clearSelection(); + + editor.moveLinesUp(); + assert.equal(["11", "22", "33", "44"].join("\n"), session.toString()); + assert.position(editor.getCursorPosition(), 1, 1); + }, + + "test: copy lines down should select lines and place cursor at the selection start" : function() { + var session = new EditSession(["11", "22", "33", "44"].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 1); + editor.getSelection().selectDown(); + + editor.copyLinesDown(); + assert.equal(["11", "22", "33", "22", "33", "44"].join("\n"), session.toString()); + + assert.position(editor.getCursorPosition(), 3, 0); + assert.position(editor.getSelection().getSelectionAnchor(), 5, 0); + assert.position(editor.getSelection().getSelectionLead(), 3, 0); + }, + + "test: copy lines up should select lines and place cursor at the selection start" : function() { + var session = new EditSession(["11", "22", "33", "44"].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 1); + editor.getSelection().selectDown(); + + editor.copyLinesUp(); + assert.equal(["11", "22", "33", "22", "33", "44"].join("\n"), session.toString()); + + assert.position(editor.getCursorPosition(), 1, 0); + assert.position(editor.getSelection().getSelectionAnchor(), 3, 0); + assert.position(editor.getSelection().getSelectionLead(), 1, 0); + }, + + "test: input a tab with soft tab should convert it to spaces" : function() { + var session = new EditSession(""); + var editor = new Editor(new MockRenderer(), session); + + session.setTabSize(2); + session.setUseSoftTabs(true); + + editor.onTextInput("\t"); + assert.equal(session.toString(), " "); + + session.setTabSize(5); + editor.onTextInput("\t"); + assert.equal(session.toString(), " "); + }, + + "test: input tab without soft tabs should keep the tab character" : function() { + var session = new EditSession(""); + var editor = new Editor(new MockRenderer(), session); + + session.setUseSoftTabs(false); + + editor.onTextInput("\t"); + assert.equal(session.toString(), "\t"); + }, + + "test: undo/redo for delete line" : function() { + var session = new EditSession(["111", "222", "333"]); + var undoManager = new UndoManager(); + session.setUndoManager(undoManager); + + var initialText = session.toString(); + var editor = new Editor(new MockRenderer(), session); + + editor.removeLines(); + var step1 = session.toString(); + assert.equal(step1, "222\n333"); + session.$syncInformUndoManager(); + + editor.removeLines(); + var step2 = session.toString(); + assert.equal(step2, "333"); + session.$syncInformUndoManager(); + + editor.removeLines(); + var step3 = session.toString(); + assert.equal(step3, ""); + session.$syncInformUndoManager(); + + undoManager.undo(); + session.$syncInformUndoManager(); + assert.equal(session.toString(), step2); + + undoManager.undo(); + session.$syncInformUndoManager(); + assert.equal(session.toString(), step1); + + undoManager.undo(); + session.$syncInformUndoManager(); + assert.equal(session.toString(), initialText); + + undoManager.undo(); + session.$syncInformUndoManager(); + assert.equal(session.toString(), initialText); + }, + + "test: remove left should remove character left of the cursor" : function() { + var session = new EditSession(["123", "456"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 1); + editor.remove("left"); + assert.equal(session.toString(), "123\n56"); + }, + + "test: remove left should remove line break if cursor is at line start" : function() { + var session = new EditSession(["123", "456"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 0); + editor.remove("left"); + assert.equal(session.toString(), "123456"); + }, + + "test: remove left should remove tabsize spaces if cursor is on a tab stop and preceeded by spaces" : function() { + var session = new EditSession(["123", " 456"]); + session.setUseSoftTabs(true); + session.setTabSize(4); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 8); + editor.remove("left"); + assert.equal(session.toString(), "123\n 456"); + }, + + "test: transpose at line start should be a noop": function() { + var session = new EditSession(["123", "4567", "89"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 0); + editor.transposeLetters(); + + assert.equal(session.getValue(), ["123", "4567", "89"].join("\n")); + }, + + "test: transpose in line should swap the charaters before and after the cursor": function() { + var session = new EditSession(["123", "4567", "89"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 2); + editor.transposeLetters(); + + assert.equal(session.getValue(), ["123", "4657", "89"].join("\n")); + }, + + "test: transpose at line end should swap the last two characters": function() { + var session = new EditSession(["123", "4567", "89"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 4); + editor.transposeLetters(); + + assert.equal(session.getValue(), ["123", "4576", "89"].join("\n")); + }, + + "test: transpose with non empty selection should be a noop": function() { + var session = new EditSession(["123", "4567", "89"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 1); + editor.getSelection().selectRight(); + editor.transposeLetters(); + + assert.equal(session.getValue(), ["123", "4567", "89"].join("\n")); + }, + + "test: transpose should move the cursor behind the last swapped character": function() { + var session = new EditSession(["123", "4567", "89"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 2); + editor.transposeLetters(); + assert.position(editor.getCursorPosition(), 1, 3); + }, + + "test: remove to line end": function() { + var session = new EditSession(["123", "4567", "89"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 2); + editor.removeToLineEnd(); + assert.equal(session.getValue(), ["123", "45", "89"].join("\n")); + }, + + "test: remove to line end at line end should remove the new line": function() { + var session = new EditSession(["123", "4567", "89"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 4); + editor.removeToLineEnd(); + assert.position(editor.getCursorPosition(), 1, 4); + assert.equal(session.getValue(), ["123", "456789"].join("\n")); + }, + + "test: transform selection to uppercase": function() { + var session = new EditSession(["ajax", "dot", "org"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 0); + editor.getSelection().selectLineEnd(); + editor.toUpperCase() + assert.equal(session.getValue(), ["ajax", "DOT", "org"].join("\n")); + }, + + "test: transform word to uppercase": function() { + var session = new EditSession(["ajax", "dot", "org"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 0); + editor.toUpperCase() + assert.equal(session.getValue(), ["ajax", "DOT", "org"].join("\n")); + assert.position(editor.getCursorPosition(), 1, 0); + }, + + "test: transform selection to lowercase": function() { + var session = new EditSession(["AJAX", "DOT", "ORG"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 0); + editor.getSelection().selectLineEnd(); + editor.toLowerCase() + assert.equal(session.getValue(), ["AJAX", "dot", "ORG"].join("\n")); + }, + + "test: transform word to lowercase": function() { + var session = new EditSession(["AJAX", "DOT", "ORG"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 0); + editor.toLowerCase() + assert.equal(session.getValue(), ["AJAX", "dot", "ORG"].join("\n")); + assert.position(editor.getCursorPosition(), 1, 0); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec() +} diff --git a/lib/ace/ext/static.css b/lib/ace/ext/static.css new file mode 100644 index 0000000000..7d785b49ff --- /dev/null +++ b/lib/ace/ext/static.css @@ -0,0 +1,22 @@ +.ace_editor { + font-family: 'Monaco', 'Menlo', 'Droid Sans Mono', 'Courier New', monospace; + font-size: 12px; +} + +.ace_editor .ace_gutter { + width: 25px !important; + display: block; + float: left; + text-align: right; + padding: 0 3px 0 0; + margin-right: 3px; +} + +.ace_line { clear: both; } + +*.ace_gutter-cell { + -moz-user-select: -moz-none; + -khtml-user-select: none; + -webkit-user-select: none; + user-select: none; +} \ No newline at end of file diff --git a/lib/ace/ext/static_highlight.js b/lib/ace/ext/static_highlight.js new file mode 100644 index 0000000000..aa8c4ce653 --- /dev/null +++ b/lib/ace/ext/static_highlight.js @@ -0,0 +1,88 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var EditSession = require("../edit_session").EditSession; +var TextLayer = require("../layer/text").Text; +var baseStyles = require("../requirejs/text!./static.css"); + +/* Transforms a given input code snippet into HTML using the given mode +* +* @param {string} input Code snippet +* @param {mode} mode Mode loaded from /ace/mode (use 'ServerSideHiglighter.getMode') +* @param {string} r Code snippet +* @returns {object} An object containing: html, css +*/ + +exports.render = function(input, mode, theme, lineStart, disableGutter) { + lineStart = parseInt(lineStart || 1, 10); + + var session = new EditSession(""); + session.setMode(mode); + session.setUseWorker(false); + + var textLayer = new TextLayer(document.createElement("div")); + textLayer.setSession(session); + textLayer.config = { + characterWidth: 10, + lineHeight: 20 + }; + + session.setValue(input); + + var stringBuilder = []; + var length = session.getLength(); + + for(var ix = 0; ix < length; ix++) { + stringBuilder.push("
"); + if (!disableGutter) + stringBuilder.push("" + (ix + lineStart) + ""); + textLayer.$renderLine(stringBuilder, ix, true, false); + stringBuilder.push("
"); + } + + // let's prepare the whole html + var html = "
\ +
\ + :code\ +
\ +
".replace(/:cssClass/, theme.cssClass).replace(/:code/, stringBuilder.join("")); + + textLayer.destroy(); + + return { + css: baseStyles + theme.cssText, + html: html + }; +}; + +}); diff --git a/lib/ace/ext/static_highlight_test.js b/lib/ace/ext/static_highlight_test.js new file mode 100644 index 0000000000..707d00eaba --- /dev/null +++ b/lib/ace/ext/static_highlight_test.js @@ -0,0 +1,76 @@ +if (typeof process !== "undefined") { + require("amd-loader"); + require("../test/mockdom"); +} + +define(function(require, exports, module) { +"use strict"; + +var assert = require("assert"); +var highlighter = require("./static_highlight"); +var JavaScriptMode = require("../mode/javascript").Mode; + +// Execution ORDER: test.setUpSuite, setUp, testFn, tearDown, test.tearDownSuite +module.exports = { + timeout: 10000, + + "test simple snippet": function(next) { + var theme = require("../theme/tomorrow"); + var snippet = "\ +/** this is a function\n\ +*\n\ +*/\n\ +function hello (a, b, c) {\n\ + console.log(a * b + c + 'sup?');\n\ +}"; + var mode = new JavaScriptMode(); + + var result = highlighter.render(snippet, mode, theme); + assert.equal(result.html, "
1/** this is a function
2*
3*/
4function hello (abc) {
5    console.log(a * b + c + 'sup?');
6}
"); + assert.ok(!!result.css); + next(); + }, + + "test css from theme is used": function(next) { + var theme = require("../theme/tomorrow"); + var snippet = "\ +/** this is a function\n\ +*\n\ +*/\n\ +function hello (a, b, c) {\n\ + console.log(a * b + c + 'sup?');\n\ +}"; + var mode = new JavaScriptMode(); + + var isError = false, result; + result = highlighter.render(snippet, mode, theme); + + assert.ok(result.css.indexOf(theme.cssText) !== -1); + + next(); + }, + + "test theme classname should be in output html": function (next) { + var theme = require("../theme/tomorrow"); + var snippet = "\ +/** this is a function\n\ +*\n\ +*/\n\ +function hello (a, b, c) {\n\ + console.log(a * b + c + 'sup?');\n\ +}"; + var mode = new JavaScriptMode(); + + var isError = false, result; + result = highlighter.render(snippet, mode, theme); + assert.equal(!!result.html.match(/
/), true); + + next(); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/lib/ace/ext/textarea.js b/lib/ace/ext/textarea.js new file mode 100644 index 0000000000..a8f6317f62 --- /dev/null +++ b/lib/ace/ext/textarea.js @@ -0,0 +1,526 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var event = require("../lib/event"); +var UA = require("../lib/useragent"); +var net = require("../lib/net"); +var ace = require("../ace"); + +require("../theme/textmate"); + +module.exports = exports = ace; + +/* + * Returns the CSS property of element. + * 1) If the CSS property is on the style object of the element, use it, OR + * 2) Compute the CSS property + * + * If the property can't get computed, is 'auto' or 'intrinsic', the former + * calculated property is used (this can happen in cases where the textarea + * is hidden and has no dimension styles). + */ +var getCSSProperty = function(element, container, property) { + var ret = element.style[property]; + + if (!ret) { + if (window.getComputedStyle) { + ret = window.getComputedStyle(element, '').getPropertyValue(property); + } else { + ret = element.currentStyle[property]; + } + } + + if (!ret || ret == 'auto' || ret == 'intrinsic') { + ret = container.style[property]; + } + return ret; +}; + +function applyStyles(elm, styles) { + for (var style in styles) { + elm.style[style] = styles[style]; + } +} + +function setupContainer(element, getValue) { + if (element.type != 'textarea') { + throw "Textarea required!"; + } + + var parentNode = element.parentNode; + + // This will hold the editor. + var container = document.createElement('div'); + + // To put Ace in the place of the textarea, we have to copy a few of the + // textarea's style attributes to the div container. + // + // The problem is that the properties have to get computed (they might be + // defined by a CSS file on the page - you can't access such rules that + // apply to an element via elm.style). Computed properties are converted to + // pixels although the dimension might be given as percentage. When the + // window resizes, the dimensions defined by percentages changes, so the + // properties have to get recomputed to get the new/true pixels. + var resizeEvent = function() { + var style = 'position:relative;'; + [ + 'margin-top', 'margin-left', 'margin-right', 'margin-bottom' + ].forEach(function(item) { + style += item + ':' + + getCSSProperty(element, container, item) + ';'; + }); + + // Calculating the width/height of the textarea is somewhat tricky. To + // do it right, you have to include the paddings to the sides as well + // (eg. width = width + padding-left, -right). This works well, as + // long as the width of the element is not set or given in pixels. In + // this case and after the textarea is hidden, getCSSProperty(element, + // container, 'width') will still return pixel value. If the element + // has realtiv dimensions (e.g. width='95') + // getCSSProperty(...) will return pixel values only as long as the + // textarea is visible. After it is hidden getCSSProperty will return + // the relative dimensions as they are set on the element (in the case + // of width, 95). + // Making the sum of pixel vaules (e.g. padding) and realtive values + // (e.g. ) is not possible. As such the padding styles are + // ignored. + + // The complete width is the width of the textarea + the padding + // to the left and right. + var width = getCSSProperty(element, container, 'width') || (element.clientWidth + "px"); + var height = getCSSProperty(element, container, 'height') || (element.clientHeight + "px"); + style += 'height:' + height + ';width:' + width + ';'; + + // Set the display property to 'inline-block'. + style += 'display:inline-block;'; + container.setAttribute('style', style); + }; + event.addListener(window, 'resize', resizeEvent); + + // Call the resizeEvent once, so that the size of the container is + // calculated. + resizeEvent(); + + // Insert the div container after the element. + if (element.nextSibling) { + parentNode.insertBefore(container, element.nextSibling); + } else { + parentNode.appendChild(container); + } + + // Override the forms onsubmit function. Set the innerHTML and value + // of the textarea before submitting. + while (parentNode !== document) { + if (parentNode.tagName.toUpperCase() === 'FORM') { + var oldSumit = parentNode.onsubmit; + // Override the onsubmit function of the form. + parentNode.onsubmit = function(evt) { + element.innerHTML = getValue(); + element.value = getValue(); + // If there is a onsubmit function already, then call + // it with the current context and pass the event. + if (oldSumit) { + oldSumit.call(this, evt); + } + }; + break; + } + parentNode = parentNode.parentNode; + } + return container; +} + +exports.transformTextarea = function(element, loader) { + var session; + var container = setupContainer(element, function() { + return session.getValue(); + }); + + // Hide the element. + element.style.display = 'none'; + container.style.background = 'white'; + + // + var editorDiv = document.createElement("div"); + applyStyles(editorDiv, { + top: "0px", + left: "0px", + right: "0px", + bottom: "0px", + border: "1px solid gray" + }); + container.appendChild(editorDiv); + + var settingOpener = document.createElement("div"); + applyStyles(settingOpener, { + position: "absolute", + right: "0px", + bottom: "0px", + background: "red", + cursor: "nw-resize", + borderStyle: "solid", + borderWidth: "9px 8px 10px 9px", + width: "2px", + borderColor: "lightblue gray gray lightblue", + zIndex: 101 + }); + + var settingDiv = document.createElement("div"); + var settingDivStyles = { + top: "0px", + left: "0px", + right: "0px", + bottom: "0px", + position: "absolute", + padding: "5px", + zIndex: 100, + color: "white", + display: "none", + overflow: "auto", + fontSize: "14px" + }; + if (!UA.isOldIE) { + settingDivStyles.backgroundColor = "rgba(0, 0, 0, 0.6)"; + } else { + settingDivStyles.backgroundColor = "#333"; + } + + applyStyles(settingDiv, settingDivStyles); + container.appendChild(settingDiv); + + // Power up ace on the textarea: + var options = {}; + + var editor = ace.edit(editorDiv); + session = editor.getSession(); + + session.setValue(element.value || element.innerHTML); + editor.focus(); + + // Add the settingPanel opener to the editor's div. + editorDiv.appendChild(settingOpener); + + // Create the API. + setupApi(editor, editorDiv, settingDiv, ace, options, loader); + + // Create the setting's panel. + setupSettingPanel(settingDiv, settingOpener, editor, options); + + var state = ""; + event.addListener(settingOpener, "mousemove", function(e) { + var rect = this.getBoundingClientRect(); + var x = e.clientX - rect.left, y = e.clientY - rect.top; + if (x + y < (rect.width + rect.height)/2) { + this.style.cursor = "pointer"; + state = "toggle"; + } else { + state = "resize"; + this.style.cursor = "nw-resize"; + } + }); + + event.addListener(settingOpener, "mousedown", function(e) { + if (state == "toggle") { + editor.setDisplaySettings(); + return; + } + container.style.zIndex = 100000; + var rect = container.getBoundingClientRect(); + var startX = rect.width + rect.left - e.clientX; + var startY = rect.height + rect.top - e.clientY; + event.capture(settingOpener, function(e) { + container.style.width = e.clientX - rect.left + startX + "px"; + container.style.height = e.clientY - rect.top + startY + "px"; + editor.resize(); + }, function() {}); + }); + + return editor; +}; + +function load(url, module, callback) { + net.loadScript(url, function() { + require([module], callback); + }); +} + +function setupApi(editor, editorDiv, settingDiv, ace, options, loader) { + var session = editor.getSession(); + var renderer = editor.renderer; + loader = loader || load; + + function toBool(value) { + return value == "true"; + } + + editor.setDisplaySettings = function(display) { + if (display == null) + display = settingDiv.style.display == "none"; + settingDiv.style.display = display ? "block" : "none"; + }; + + editor.setOption = function(key, value) { + if (options[key] == value) return; + + switch (key) { + case "gutter": + renderer.setShowGutter(toBool(value)); + break; + + case "mode": + if (value != "text") { + // Load the required mode file. Files get loaded only once. + loader("mode-" + value + ".js", "ace/mode/" + value, function() { + var aceMode = require("../mode/" + value).Mode; + session.setMode(new aceMode()); + }); + } else { + session.setMode(new (require("../mode/text").Mode)); + } + break; + + case "theme": + if (value != "textmate") { + // Load the required theme file. Files get loaded only once. + loader("theme-" + value + ".js", "ace/theme/" + value, function() { + editor.setTheme("ace/theme/" + value); + }); + } else { + editor.setTheme("ace/theme/textmate"); + } + break; + + case "fontSize": + editorDiv.style.fontSize = value; + break; + + case "softWrap": + switch (value) { + case "off": + session.setUseWrapMode(false); + renderer.setPrintMarginColumn(80); + break; + case "40": + session.setUseWrapMode(true); + session.setWrapLimitRange(40, 40); + renderer.setPrintMarginColumn(40); + break; + case "80": + session.setUseWrapMode(true); + session.setWrapLimitRange(80, 80); + renderer.setPrintMarginColumn(80); + break; + case "free": + session.setUseWrapMode(true); + session.setWrapLimitRange(null, null); + renderer.setPrintMarginColumn(80); + break; + } + break; + + case "useSoftTabs": + session.setUseSoftTabs(toBool(value)); + break; + + case "showPrintMargin": + renderer.setShowPrintMargin(toBool(value)); + break; + + case "showInvisibles": + editor.setShowInvisibles(toBool(value)); + break; + } + + options[key] = value; + }; + + editor.getOption = function(key) { + return options[key]; + }; + + editor.getOptions = function() { + return options; + }; + + for (var option in exports.options) { + editor.setOption(option, exports.options[option]); + } + + return editor; +} + +function setupSettingPanel(settingDiv, settingOpener, editor, options) { + var BOOL = { + "true": true, + "false": false + }; + + var desc = { + mode: "Mode:", + gutter: "Display Gutter:", + theme: "Theme:", + fontSize: "Font Size:", + softWrap: "Soft Wrap:", + showPrintMargin: "Show Print Margin:", + useSoftTabs: "Use Soft Tabs:", + showInvisibles: "Show Invisibles" + }; + + var optionValues = { + mode: { + text: "Plain", + javascript: "JavaScript", + xml: "XML", + html: "HTML", + css: "CSS", + scss: "SCSS", + python: "Python", + php: "PHP", + java: "Java", + ruby: "Ruby", + c_cpp: "C/C++", + coffee: "CoffeeScript", + json: "json", + perl: "Perl", + clojure: "Clojure", + ocaml: "OCaml", + csharp: "C#", + haxe: "haXe", + svg: "SVG", + textile: "Textile", + groovy: "Groovy", + liquid: "Liquid", + Scala: "Scala" + }, + theme: { + clouds: "Clouds", + clouds_midnight: "Clouds Midnight", + cobalt: "Cobalt", + crimson_editor: "Crimson Editor", + dawn: "Dawn", + eclipse: "Eclipse", + idle_fingers: "Idle Fingers", + kr_theme: "Kr Theme", + merbivore: "Merbivore", + merbivore_soft: "Merbivore Soft", + mono_industrial: "Mono Industrial", + monokai: "Monokai", + pastel_on_dark: "Pastel On Dark", + solarized_dark: "Solarized Dark", + solarized_light: "Solarized Light", + textmate: "Textmate", + twilight: "Twilight", + vibrant_ink: "Vibrant Ink" + }, + gutter: BOOL, + fontSize: { + "10px": "10px", + "11px": "11px", + "12px": "12px", + "14px": "14px", + "16px": "16px" + }, + softWrap: { + off: "Off", + 40: "40", + 80: "80", + free: "Free" + }, + showPrintMargin: BOOL, + useSoftTabs: BOOL, + showInvisibles: BOOL + }; + + var table = []; + table.push(""); + + function renderOption(builder, option, obj, cValue) { + builder.push(""); + } + + for (var option in options) { + table.push(""); + table.push(""); + } + table.push("
SettingValue
", desc[option], ""); + renderOption(table, option, optionValues[option], options[option]); + table.push("
"); + settingDiv.innerHTML = table.join(""); + + var selects = settingDiv.getElementsByTagName("select"); + for (var i = 0; i < selects.length; i++) { + var onChange = (function() { + var select = selects[i]; + return function() { + var option = select.title; + var value = select.value; + editor.setOption(option, value); + }; + })(); + selects[i].onchange = onChange; + } + + var button = document.createElement("input"); + button.type = "button"; + button.value = "Hide"; + event.addListener(button, "click", function() { + editor.setDisplaySettings(false); + }); + settingDiv.appendChild(button); +} + +// Default startup options. +exports.options = { + mode: "text", + theme: "textmate", + gutter: "false", + fontSize: "12px", + softWrap: "off", + showPrintMargin: "false", + useSoftTabs: "true", + showInvisibles: "true" +}; + +}); diff --git a/lib/ace/keyboard/emacs.js b/lib/ace/keyboard/emacs.js new file mode 100644 index 0000000000..8fc3aeeb3a --- /dev/null +++ b/lib/ace/keyboard/emacs.js @@ -0,0 +1,375 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var dom = require("../lib/dom"); + +var screenToTextBlockCoordinates = function(pageX, pageY) { + var canvasPos = this.scroller.getBoundingClientRect(); + + var col = Math.floor( + (pageX + this.scrollLeft - canvasPos.left - this.$padding - dom.getPageScrollLeft()) / this.characterWidth + ); + var row = Math.floor( + (pageY + this.scrollTop - canvasPos.top - dom.getPageScrollTop()) / this.lineHeight + ); + + return this.session.screenToDocumentPosition(row, col); +}; + +var HashHandler = require("./hash_handler").HashHandler; +exports.handler = new HashHandler(); + +var initialized = false; +exports.handler.attach = function(editor) { + if (!initialized) { + initialized = true; + dom.importCssString('\ + .emacs-mode .ace_cursor{\ + border: 2px rgba(50,250,50,0.8) solid!important;\ + -moz-box-sizing: border-box!important;\ + -webkit-box-sizing: border-box!important;\ + box-sizing: border-box!important;\ + background-color: rgba(0,250,0,0.9);\ + opacity: 0.5;\ + }\ + .emacs-mode .ace_cursor.ace_hidden{\ + opacity: 1;\ + background-color: transparent;\ + }\ + .emacs-mode .ace_overwrite-cursors .ace_cursor {\ + opacity: 1;\ + background-color: transparent;\ + border-width: 0 0 2px 2px !important;\ + }\ + .emacs-mode .ace_text-layer {\ + z-index: 4\ + }\ + .emacs-mode .ace_cursor-layer {\ + z-index: 2\ + }', 'emacsMode' + ); + } + + editor.renderer.screenToTextCoordinates = screenToTextBlockCoordinates; + editor.setStyle("emacs-mode"); +}; + +exports.handler.detach = function(editor) { + delete editor.renderer.screenToTextCoordinates; + editor.unsetStyle("emacs-mode"); +}; + + +var keys = require("../lib/keys").KEY_MODS; +var eMods = { + C: "ctrl", S: "shift", M: "alt" +}; +["S-C-M", "S-C", "S-M", "C-M", "S", "C", "M"].forEach(function(c) { + var hashId = 0; + c.split("-").forEach(function(c){ + hashId = hashId | keys[eMods[c]]; + }); + eMods[hashId] = c.toLowerCase() + "-"; +}); + +exports.handler.bindKey = function(key, command) { + if (!key) + return; + + var ckb = this.commmandKeyBinding; + key.split("|").forEach(function(keyPart) { + keyPart = keyPart.toLowerCase(); + ckb[keyPart] = command; + keyPart = keyPart.split(" ")[0]; + if (!ckb[keyPart]) + ckb[keyPart] = "null"; + }, this); +}; + + +exports.handler.handleKeyboard = function(data, hashId, key, keyCode) { + if (hashId == -1) { + if (data.count) { + var str = Array(data.count + 1).join(key); + data.count = null; + return {command: "insertstring", args: str}; + } + } + + if (key == "\x00") + return; + + var modifier = eMods[hashId]; + if (modifier == "c-" || data.universalArgument) { + var count = parseInt(key[key.length - 1]); + if (count) { + data.count = count; + return {command: "null"}; + } + } + data.universalArgument = false; + + if (modifier) + key = modifier + key; + + if (data.keyChain) + key = data.keyChain += " " + key; + + var command = this.commmandKeyBinding[key]; + data.keyChain = command == "null" ? key : ""; + + if (!command) + return; + + if (command == "null") + return {command: "null"}; + + if (command == "universalArgument") { + data.universalArgument = true; + return {command: "null"}; + } + + if (typeof command != "string") { + var args = command.args; + command = command.command; + } + + if (typeof command == "string") { + command = this.commands[command] || data.editor.commands.commands[command]; + } + + if (!command.readonly && !command.isYank) + data.lastCommand = null; + + if (data.count) { + var count = data.count; + data.count = 0; + return { + args: args, + command: { + exec: function(editor, args) { + for (var i = 0; i < count; i++) + command.exec(editor, args); + } + } + }; + } + + return {command: command, args: args}; +}; + +exports.emacsKeys = { + // movement + "Up|C-p" : "golineup", + "Down|C-n" : "golinedown", + "Left|C-b" : "gotoleft", + "Right|C-f" : "gotoright", + "C-Left|M-b" : "gotowordleft", + "C-Right|M-f" : "gotowordright", + "Home|C-a" : "gotolinestart", + "End|C-e" : "gotolineend", + "C-Home|S-M-,": "gotostart", + "C-End|S-M-." : "gotoend", + + // selection + "S-Up|S-C-p" : "selectup", + "S-Down|S-C-n" : "selectdown", + "S-Left|S-C-b" : "selectleft", + "S-Right|S-C-f" : "selectright", + "S-C-Left|S-M-b" : "selectwordleft", + "S-C-Right|S-M-f" : "selectwordright", + "S-Home|S-C-a" : "selecttolinestart", + "S-End|S-C-e" : "selecttolineend", + "S-C-Home" : "selecttostart", + "S-C-End" : "selecttoend", + + "C-l" : "recenterTopBottom", + "M-s" : "centerselection", + "M-g": "gotoline", + "C-x C-p": "selectall", + + // todo fix these + "C-Down": "gotopagedown", + "C-Up": "gotopageup", + "PageDown|C-v": "gotopagedown", + "PageUp|M-v": "gotopageup", + "S-C-Down": "selectpagedown", + "S-C-Up": "selectpageup", + "C-s": "findnext", + "C-r": "findprevious", + "M-C-s": "findnext", + "M-C-r": "findprevious", + "S-M-5": "replace", + + // basic editing + "Backspace": "backspace", + "Delete|C-d": "del", + "Return|C-m": {command: "insertstring", args: "\n"}, // "newline" + "C-o": "splitline", + + "M-d|C-Delete": {command: "killWord", args: "right"}, + "C-Backspace|M-Backspace|M-Delete": {command: "killWord", args: "left"}, + "C-k": "killLine", + + "C-y|S-Delete": "yank", + "M-y": "yankRotate", + "C-g": "keyboardQuit", + + "C-w": "killRegion", + "M-w": "killRingSave", + + "C-Space": "setMark", + "C-x C-x": "exchangePointAndMark", + + "C-t": "transposeletters", + + "M-u": "touppercase", + "M-l": "tolowercase", + "M-/": "autocomplete", + "C-u": "universalArgument", + "M-;": "togglecomment", + + "C-/|C-x u|S-C--|C-z": "undo", + "S-C-/|S-C-x u|C--|S-C-z": "redo", //infinite undo? + // vertical editing + "C-x r": "selectRectangularRegion" + + // todo + // "M-x" "C-x C-t" "M-t" "M-c" "F11" "C-M- "M-q" +}; + + +exports.handler.bindKeys(exports.emacsKeys); + +exports.handler.addCommands({ + recenterTopBottom: function(editor) { + var renderer = editor.renderer; + var pos = renderer.$cursorLayer.getPixelPosition(); + var h = renderer.$size.scrollerHeight - renderer.lineHeight; + var scrollTop = renderer.scrollTop; + if (Math.abs(pos.top - scrollTop) < 2) { + scrollTop = pos.top - h; + } else if (Math.abs(pos.top - scrollTop - h * 0.5) < 2) { + scrollTop = pos.top; + } else { + scrollTop = pos.top - h * 0.5; + } + editor.session.setScrollTop(scrollTop); + }, + selectRectangularRegion: function(editor) { + editor.multiSelect.toggleBlockSelection(); + }, + setMark: function() { + }, + exchangePointAndMark: { + exec: function(editor) { + var range = editor.selection.getRange(); + editor.selection.setSelectionRange(range, !editor.selection.isBackwards()); + }, + readonly: true, + multiselectAction: "forEach" + }, + killWord: { + exec: function(editor, dir) { + editor.clearSelection(); + if (dir == "left") + editor.selection.selectWordLeft(); + else + editor.selection.selectWordRight(); + + var range = editor.getSelectionRange(); + var text = editor.session.getTextRange(range); + exports.killRing.add(text); + + editor.session.remove(range); + editor.clearSelection(); + }, + multiselectAction: "forEach" + }, + killLine: function(editor) { + editor.selection.selectLine(); + var range = editor.getSelectionRange(); + var text = editor.session.getTextRange(range); + exports.killRing.add(text); + + editor.session.remove(range); + editor.clearSelection(); + }, + yank: function(editor) { + editor.onPaste(exports.killRing.get()); + editor.keyBinding.$data.lastCommand = "yank"; + }, + yankRotate: function(editor) { + if (editor.keyBinding.$data.lastCommand != "yank") + return; + + editor.undo(); + editor.onPaste(exports.killRing.rotate()); + editor.keyBinding.$data.lastCommand = "yank"; + }, + killRegion: function(editor) { + exports.killRing.add(editor.getCopyText()); + editor.commands.byName.cut.exec(editor); + }, + killRingSave: function(editor) { + exports.killRing.add(editor.getCopyText()); + } +}); + +var commands = exports.handler.commands; +commands.yank.isYank = true; +commands.yankRotate.isYank = true; + +exports.killRing = { + $data: [], + add: function(str) { + str && this.$data.push(str); + if (this.$data.length > 30) + this.$data.shift(); + }, + get: function() { + return this.$data[this.$data.length - 1] || ""; + }, + pop: function() { + if (this.$data.length > 1) + this.$data.pop(); + return this.get(); + }, + rotate: function() { + this.$data.unshift(this.$data.pop()); + return this.get(); + } +}; + + +}); diff --git a/lib/ace/keyboard/hash_handler.js b/lib/ace/keyboard/hash_handler.js new file mode 100644 index 0000000000..92001c02d7 --- /dev/null +++ b/lib/ace/keyboard/hash_handler.js @@ -0,0 +1,163 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var keyUtil = require("../lib/keys"); + +function HashHandler(config, platform) { + this.platform = platform; + this.commands = {}; + this.commmandKeyBinding = {}; + + this.addCommands(config); +}; + +(function() { + + this.addCommand = function(command) { + if (this.commands[command.name]) + this.removeCommand(command); + + this.commands[command.name] = command; + + if (command.bindKey) + this._buildKeyHash(command); + }; + + this.removeCommand = function(command) { + var name = (typeof command === 'string' ? command : command.name); + command = this.commands[name]; + delete this.commands[name]; + + // exhaustive search is brute force but since removeCommand is + // not a performance critical operation this should be OK + var ckb = this.commmandKeyBinding; + for (var hashId in ckb) { + for (var key in ckb[hashId]) { + if (ckb[hashId][key] == command) + delete ckb[hashId][key]; + } + } + }; + + this.bindKey = function(key, command) { + if(!key) + return; + if (typeof command == "function") { + this.addCommand({exec: command, bindKey: key, name: key}); + return; + } + + var ckb = this.commmandKeyBinding; + key.split("|").forEach(function(keyPart) { + var binding = this.parseKeys(keyPart, command); + var hashId = binding.hashId; + (ckb[hashId] || (ckb[hashId] = {}))[binding.key] = command; + }, this); + }; + + this.addCommands = function(commands) { + commands && Object.keys(commands).forEach(function(name) { + var command = commands[name]; + if (typeof command === "string") + return this.bindKey(command, name); + + if (typeof command === "function") + command = { exec: command }; + + if (!command.name) + command.name = name; + + this.addCommand(command); + }, this); + }; + + this.removeCommands = function(commands) { + Object.keys(commands).forEach(function(name) { + this.removeCommand(commands[name]); + }, this); + }; + + this.bindKeys = function(keyList) { + Object.keys(keyList).forEach(function(key) { + this.bindKey(key, keyList[key]); + }, this); + }; + + this._buildKeyHash = function(command) { + var binding = command.bindKey; + if (!binding) + return; + + var key = typeof binding == "string" ? binding: binding[this.platform]; + this.bindKey(key, command); + }; + + // accepts keys in the form ctrl+Enter or ctrl-Enter + // keys without modifiers or shift only + this.parseKeys = function(keys) { + var parts = keys.toLowerCase().split(/[\-\+]([\-\+])?/).filter(function(x){return x}); + var key = parts.pop(); + + var keyCode = keyUtil[key]; + if (keyUtil.FUNCTION_KEYS[keyCode]) + key = keyUtil.FUNCTION_KEYS[keyCode].toLowerCase(); + else if (!parts.length) + return {key: key, hashId: -1}; + else if (parts.length == 1 && parts[0] == "shift") + return {key: key.toUpperCase(), hashId: -1}; + + var hashId = 0; + for (var i = parts.length; i--;) { + var modifier = keyUtil.KEY_MODS[parts[i]]; + if (modifier == null) + throw "invalid modifier " + parts[i] + " in " + keys; + hashId |= modifier; + } + return {key: key, hashId: hashId}; + }; + + this.findKeyCommand = function findKeyCommand(hashId, keyString) { + var ckbr = this.commmandKeyBinding; + return ckbr[hashId] && ckbr[hashId][keyString]; + }; + + this.handleKeyboard = function(data, hashId, keyString, keyCode) { + return { + command: this.findKeyCommand(hashId, keyString) + }; + }; + +}).call(HashHandler.prototype) + +exports.HashHandler = HashHandler; +}); diff --git a/lib/ace/keyboard/keybinding.js b/lib/ace/keyboard/keybinding.js new file mode 100644 index 0000000000..f92d1f6fac --- /dev/null +++ b/lib/ace/keyboard/keybinding.js @@ -0,0 +1,134 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var keyUtil = require("../lib/keys"); +var event = require("../lib/event"); + +var KeyBinding = function(editor) { + this.$editor = editor; + this.$data = { }; + this.$handlers = []; + this.setDefaultHandler(editor.commands); +}; + +(function() { + this.setDefaultHandler = function(kb) { + this.removeKeyboardHandler(this.$defaultHandler); + this.$defaultHandler = kb; + this.addKeyboardHandler(kb, 0); + this.$data = {editor: this.$editor}; + }; + + this.setKeyboardHandler = function(kb) { + if (this.$handlers[this.$handlers.length - 1] == kb) + return; + + while (this.$handlers[1]) + this.removeKeyboardHandler(this.$handlers[1]); + + this.addKeyboardHandler(kb, 1); + }; + + this.addKeyboardHandler = function(kb, pos) { + if (!kb) + return; + var i = this.$handlers.indexOf(kb); + if (i != -1) + this.$handlers.splice(i, 1); + + if (pos == undefined) + this.$handlers.push(kb); + else + this.$handlers.splice(pos, 0, kb); + + if (i == -1 && kb.attach) + kb.attach(this.$editor); + }; + + this.removeKeyboardHandler = function(kb) { + var i = this.$handlers.indexOf(kb); + if (i == -1) + return false; + this.$handlers.splice(i, 1); + kb.detach && kb.detach(this.$editor); + return true; + }; + + this.getKeyboardHandler = function() { + return this.$handlers[this.$handlers.length - 1]; + }; + + this.$callKeyboardHandlers = function (hashId, keyString, keyCode, e) { + var toExecute; + for (var i = this.$handlers.length; i--;) { + toExecute = this.$handlers[i].handleKeyboard( + this.$data, hashId, keyString, keyCode, e + ); + if (toExecute && toExecute.command) + break; + } + + if (!toExecute || !toExecute.command) + return false; + + var success = false; + var commands = this.$editor.commands; + + // allow keyboardHandler to consume keys + if (toExecute.command != "null") + success = commands.exec(toExecute.command, this.$editor, toExecute.args, e); + else + success = toExecute.passEvent != true; + + // do not stop input events to not break repeating + if (success && e && hashId != -1) + event.stopEvent(e); + + return success; + }; + + this.onCommandKey = function(e, hashId, keyCode) { + var keyString = keyUtil.keyCodeToString(keyCode); + this.$callKeyboardHandlers(hashId, keyString, keyCode, e); + }; + + this.onTextInput = function(text) { + var success = this.$callKeyboardHandlers(-1, text); + if (!success) + this.$editor.commands.exec("insertstring", this.$editor, text); + }; + +}).call(KeyBinding.prototype); + +exports.KeyBinding = KeyBinding; +}); diff --git a/lib/ace/keyboard/state_handler.js b/lib/ace/keyboard/state_handler.js new file mode 100644 index 0000000000..6108eab7d7 --- /dev/null +++ b/lib/ace/keyboard/state_handler.js @@ -0,0 +1,250 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +// If you're developing a new keymapping and want to get an idea what's going +// on, then enable debugging. +var DEBUG = false; + +function StateHandler(keymapping) { + this.keymapping = this.$buildKeymappingRegex(keymapping); +} + +StateHandler.prototype = { + /* + * Build the RegExp from the keymapping as RegExp can't stored directly + * in the metadata JSON and as the RegExp used to match the keys/buffer + * need to be adapted. + */ + $buildKeymappingRegex: function(keymapping) { + for (var state in keymapping) { + this.$buildBindingsRegex(keymapping[state]); + } + return keymapping; + }, + + $buildBindingsRegex: function(bindings) { + // Escape a given Regex string. + bindings.forEach(function(binding) { + if (binding.key) { + binding.key = new RegExp('^' + binding.key + '$'); + } else if (Array.isArray(binding.regex)) { + if (!('key' in binding)) + binding.key = new RegExp('^' + binding.regex[1] + '$'); + binding.regex = new RegExp(binding.regex.join('') + '$'); + } else if (binding.regex) { + binding.regex = new RegExp(binding.regex + '$'); + } + }); + }, + + $composeBuffer: function(data, hashId, key, e) { + // Initialize the data object. + if (data.state == null || data.buffer == null) { + data.state = "start"; + data.buffer = ""; + } + + var keyArray = []; + if (hashId & 1) keyArray.push("ctrl"); + if (hashId & 8) keyArray.push("command"); + if (hashId & 2) keyArray.push("option"); + if (hashId & 4) keyArray.push("shift"); + if (key) keyArray.push(key); + + var symbolicName = keyArray.join("-"); + var bufferToUse = data.buffer + symbolicName; + + // Don't add the symbolic name to the key buffer if the alt_ key is + // part of the symbolic name. If it starts with alt_, this means + // that the user hit an alt keycombo and there will be a single, + // new character detected after this event, which then will be + // added to the buffer (e.g. alt_j will result in ∆). + // + // We test for 2 and not for & 2 as we only want to exclude the case where + // the option key is pressed alone. + if (hashId != 2) { + data.buffer = bufferToUse; + } + + var bufferObj = { + bufferToUse: bufferToUse, + symbolicName: symbolicName + }; + + if (e) { + bufferObj.keyIdentifier = e.keyIdentifier; + } + + return bufferObj; + }, + + $find: function(data, buffer, symbolicName, hashId, key, keyIdentifier) { + // Holds the command to execute and the args if a command matched. + var result = {}; + + // Loop over all the bindings of the keymap until a match is found. + this.keymapping[data.state].some(function(binding) { + var match; + + // Check if the key matches. + if (binding.key && !binding.key.test(symbolicName)) { + return false; + } + + // Check if the regex matches. + if (binding.regex && !(match = binding.regex.exec(buffer))) { + return false; + } + + // Check if the match function matches. + if (binding.match && !binding.match(buffer, hashId, key, symbolicName, keyIdentifier)) { + return false; + } + + // Check for disallowed matches. + if (binding.disallowMatches) { + for (var i = 0; i < binding.disallowMatches.length; i++) { + if (!!match[binding.disallowMatches[i]]) { + return false; + } + } + } + + // If there is a command to execute, then figure out the + // command and the arguments. + if (binding.exec) { + result.command = binding.exec; + + // Build the arguments. + if (binding.params) { + var value; + result.args = {}; + binding.params.forEach(function(param) { + if (param.match != null && match != null) { + value = match[param.match] || param.defaultValue; + } else { + value = param.defaultValue; + } + + if (param.type === 'number') { + value = parseInt(value); + } + + result.args[param.name] = value; + }); + } + data.buffer = ""; + } + + // Handle the 'then' property. + if (binding.then) { + data.state = binding.then; + data.buffer = ""; + } + + // If no command is set, then execute the "null" fake command. + if (result.command == null) { + result.command = "null"; + } + + if (DEBUG) { + console.log("KeyboardStateMapper#find", binding); + } + return true; + }); + + if (result.command) { + return result; + } else { + data.buffer = ""; + return false; + } + }, + + /* + * This function is called by keyBinding. + */ + handleKeyboard: function(data, hashId, key, keyCode, e) { + if (hashId == -1) + hashId = 0 + // If we pressed any command key but no other key, then ignore the input. + // Otherwise "shift-" is added to the buffer, and later on "shift-g" + // which results in "shift-shift-g" which doesn't make sense. + if (hashId != 0 && (key == "" || key == String.fromCharCode(0))) { + return null; + } + + // Compute the current value of the keyboard input buffer. + var r = this.$composeBuffer(data, hashId, key, e); + var buffer = r.bufferToUse; + var symbolicName = r.symbolicName; + var keyId = r.keyIdentifier; + + r = this.$find(data, buffer, symbolicName, hashId, key, keyId); + if (DEBUG) { + console.log("KeyboardStateMapper#match", buffer, symbolicName, r); + } + + return r; + } +} + +/* + * This is a useful matching function and therefore is defined here so that + * users of KeyboardStateMapper can use it. + * + * @return boolean + * If no command key (Command|Option|Shift|Ctrl) is pressed, it + * returns true. If the only the Shift key is pressed + a character + * true is returned as well. Otherwise, false is returned. + * Summing up, the function returns true whenever the user typed + * a normal character on the keyboard and no shortcut. + */ +exports.matchCharacterOnly = function(buffer, hashId, key, symbolicName) { + // If no command keys are pressed, then catch the input. + if (hashId == 0) { + return true; + } + // If only the shift key is pressed and a character key, then + // catch that input as well. + else if ((hashId == 4) && key.length == 1) { + return true; + } + // Otherwise, we let the input got through. + else { + return false; + } +}; + +exports.StateHandler = StateHandler; +}); diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js new file mode 100644 index 0000000000..44632ef335 --- /dev/null +++ b/lib/ace/keyboard/textinput.js @@ -0,0 +1,332 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var event = require("../lib/event"); +var useragent = require("../lib/useragent"); +var dom = require("../lib/dom"); + +var TextInput = function(parentNode, host) { + var text = dom.createElement("textarea"); + text.className = "ace_text-input"; + /*/ debug + text.style.opacity = 1 + text.style.background = "rgba(0, 250, 0, 0.3)" + text.style.outline = "rgba(0, 250, 0, 0.8) solid 1px" + text.style.outlineOffset = "3px" + /**/ + if (useragent.isTouchPad) + text.setAttribute("x-palm-disable-auto-cap", true); + + text.wrap = "off"; + text.spellcheck = false; + + text.style.top = "-2em"; + parentNode.insertBefore(text, parentNode.firstChild); + + var PLACEHOLDER = useragent.isIE ? "\x01" : "\x00"; + reset(true); + if (isFocused()) + host.onFocus(); + + var inCompostion = false; + var copied = false; + var pasted = false; + var tempStyle = ''; + + function reset(full) { + try { + if (full) { + text.value = PLACEHOLDER; + text.selectionStart = 0; + text.selectionEnd = 1; + } else + text.select(); + } catch (e) {} + } + + function sendText(valueToSend) { + if (!copied) { + var value = valueToSend || text.value; + if (value) { + if (value.length > 1) { + if (value.charAt(0) == PLACEHOLDER) + value = value.substr(1); + else if (value.charAt(value.length - 1) == PLACEHOLDER) + value = value.slice(0, -1); + } + + if (value && value != PLACEHOLDER) { + if (pasted) + host.onPaste(value); + else + host.onTextInput(value); + } + } + } + + copied = false; + pasted = false; + + // Safari doesn't fire copy events if no text is selected + reset(true); + } + + var onTextInput = function(e) { + if (!inCompostion) + sendText(e.data); + setTimeout(function () { + if (!inCompostion) + reset(true); + }, 0); + }; + + var onPropertyChange = function(e) { + setTimeout(function() { + if (!inCompostion) + if(text.value != "") { + sendText(); + } + }, 0); + }; + + var onCompositionStart = function(e) { + inCompostion = true; + host.onCompositionStart(); + setTimeout(onCompositionUpdate, 0); + }; + + var onCompositionUpdate = function() { + if (!inCompostion) return; + host.onCompositionUpdate(text.value); + }; + + var onCompositionEnd = function(e) { + inCompostion = false; + host.onCompositionEnd(); + }; + + var onCopy = function(e) { + copied = true; + var copyText = host.getCopyText(); + if(copyText) + text.value = copyText; + else + e.preventDefault(); + reset(); + setTimeout(function () { + sendText(); + }, 0); + }; + + var onCut = function(e) { + copied = true; + var copyText = host.getCopyText(); + if(copyText) { + text.value = copyText; + host.onCut(); + } else + e.preventDefault(); + reset(); + setTimeout(function () { + sendText(); + }, 0); + }; + + event.addCommandKeyListener(text, host.onCommandKey.bind(host)); + event.addListener(text, "input", onTextInput); + + if (useragent.isOldIE) { + var keytable = { 13:1, 27:1 }; + event.addListener(text, "keyup", function (e) { + if (inCompostion && (!text.value || keytable[e.keyCode])) + setTimeout(onCompositionEnd, 0); + if ((text.value.charCodeAt(0)|0) < 129) { + return; + } + inCompostion ? onCompositionUpdate() : onCompositionStart(); + }); + + event.addListener(text, "propertychange", function() { + if (text.value != PLACEHOLDER) + setTimeout(sendText, 0); + }); + } + + event.addListener(text, "paste", function(e) { + // Mark that the next input text comes from past. + pasted = true; + // Some browsers support the event.clipboardData API. Use this to get + // the pasted content which increases speed if pasting a lot of lines. + if (e.clipboardData && e.clipboardData.getData) { + sendText(e.clipboardData.getData("text/plain")); + e.preventDefault(); + } + else { + // If a browser doesn't support any of the things above, use the regular + // method to detect the pasted input. + onPropertyChange(); + } + }); + + if ("onbeforecopy" in text && typeof clipboardData !== "undefined") { + event.addListener(text, "beforecopy", function(e) { + if (tempStyle) + return; // without this text is copied when contextmenu is shown + var copyText = host.getCopyText(); + if (copyText) + clipboardData.setData("Text", copyText); + else + e.preventDefault(); + }); + event.addListener(parentNode, "keydown", function(e) { + if (e.ctrlKey && e.keyCode == 88) { + var copyText = host.getCopyText(); + if (copyText) { + clipboardData.setData("Text", copyText); + host.onCut(); + } + event.preventDefault(e); + } + }); + event.addListener(text, "cut", onCut); // for ie9 context menu + } + else if (useragent.isOpera && !("KeyboardEvent" in window)) { + event.addListener(parentNode, "keydown", function(e) { + if ((useragent.isMac && !e.metaKey) || !e.ctrlKey) + return; + + if ((e.keyCode == 88 || e.keyCode == 67)) { + var copyText = host.getCopyText(); + if (copyText) { + text.value = copyText; + text.select(); + if (e.keyCode == 88) + host.onCut(); + } + } + }); + } + else { + event.addListener(text, "copy", onCopy); + event.addListener(text, "cut", onCut); + } + + event.addListener(text, "compositionstart", onCompositionStart); + if (useragent.isGecko) { + event.addListener(text, "text", onCompositionUpdate); + } + if (useragent.isWebKit) { + event.addListener(text, "keyup", onCompositionUpdate); + } + event.addListener(text, "compositionend", onCompositionEnd); + + event.addListener(text, "blur", function() { + host.onBlur(); + }); + + event.addListener(text, "focus", function() { + host.onFocus(); + reset(); + }); + + this.focus = function() { + reset(); + text.focus(); + }; + + this.blur = function() { + text.blur(); + }; + + function isFocused() { + return document.activeElement === text; + } + this.isFocused = isFocused; + + this.getElement = function() { + return text; + }; + + this.onContextMenu = function(e) { + if (!tempStyle) + tempStyle = text.style.cssText; + + text.style.cssText = + "position:fixed; z-index:100000;" + + (useragent.isIE ? "background:rgba(0, 0, 0, 0.03); opacity:0.1;" : "") + //"background:rgba(250, 0, 0, 0.3); opacity:1;" + + "left:" + (e.clientX - 2) + "px; top:" + (e.clientY - 2) + "px;"; + + if (host.selection.isEmpty()) + text.value = ""; + else + reset(true); + + if (e.type != "mousedown") + return; + + if (host.renderer.$keepTextAreaAtCursor) + host.renderer.$keepTextAreaAtCursor = null; + + // on windows context menu is opened after mouseup + if (useragent.isWin) + event.capture(host.container, function(e) { + text.style.left = e.clientX - 2 + "px"; + text.style.top = e.clientY - 2 + "px"; + }, onContextMenuClose); + }; + + function onContextMenuClose() { + setTimeout(function () { + if (tempStyle) { + text.style.cssText = tempStyle; + tempStyle = ''; + } + sendText(); + if (host.renderer.$keepTextAreaAtCursor == null) { + host.renderer.$keepTextAreaAtCursor = true; + host.renderer.$moveTextAreaToCursor(); + } + }, 0); + }; + this.onContextMenuClose = onContextMenuClose; + + // firefox fires contextmenu event after opening it + if (!useragent.isGecko) + event.addListener(text, "contextmenu", function(e) { + host.textInput.onContextMenu(e); + onContextMenuClose() + }); +}; + +exports.TextInput = TextInput; +}); diff --git a/lib/ace/keyboard/vim.js b/lib/ace/keyboard/vim.js new file mode 100644 index 0000000000..5313e44c4f --- /dev/null +++ b/lib/ace/keyboard/vim.js @@ -0,0 +1,149 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var cmds = require("./vim/commands"); +var coreCommands = cmds.coreCommands; +var util = require("./vim/maps/util"); +var useragent = require("../lib/useragent"); + +var startCommands = { + "i": { + command: coreCommands.start + }, + "I": { + command: coreCommands.startBeginning + }, + "a": { + command: coreCommands.append + }, + "A": { + command: coreCommands.appendEnd + }, + "ctrl-f": { + command: "gotopagedown" + }, + "ctrl-b": { + command: "gotopageup" + } +}; + +exports.handler = { + // workaround for j not repeating with `defaults write -g ApplePressAndHoldEnabled -bool true` + handleMacRepeat: function(data, hashId, key) { + if (hashId == -1) { + // record key + data.inputChar = key; + data.lastEvent = "input"; + } else if (data.inputChar && data.$lastHash == hashId && data.$lastKey == key) { + // check for repeated keypress + if (data.lastEvent == "input") { + data.lastEvent = "input1"; + } else if (data.lastEvent == "input1") { + // simulate textinput + return true; + } + } else { + // reset + data.$lastHash = hashId; + data.$lastKey = key; + data.lastEvent = "keypress"; + } + }, + + handleKeyboard: function(data, hashId, key, keyCode, e) { + // ignore command keys (shift, ctrl etc.) + if (hashId != 0 && (key == "" || key == "\x00")) + return null; + + if (hashId == 1) + key = "ctrl-" + key; + + if ((key == "esc" && hashId == 0) || key == "ctrl-[") { + return {command: coreCommands.stop}; + } else if (data.state == "start") { + if (useragent.isMac && this.handleMacRepeat(data, hashId, key)) { + hashId = -1; + key = data.inputChar; + } + + if (hashId == -1 || hashId == 1) { + if (cmds.inputBuffer.idle && startCommands[key]) + return startCommands[key]; + return { + command: { + exec: function(editor) {cmds.inputBuffer.push(editor, key);} + } + }; + } // if no modifier || shift: wait for input. + else if (key.length == 1 && (hashId == 0 || hashId == 4)) { + return {command: "null", passEvent: true}; + } else if (key == "esc" && hashId == 0) { + return {command: coreCommands.stop}; + } + } else { + if (key == "ctrl-w") { + return {command: "removewordleft"}; + } + } + }, + + attach: function(editor) { + editor.on("click", exports.onCursorMove); + if (util.currentMode !== "insert") + cmds.coreCommands.stop.exec(editor); + editor.$vimModeHandler = this; + }, + + detach: function(editor) { + editor.removeListener("click", exports.onCursorMove); + util.noMode(editor); + util.currentMode = "normal"; + }, + + actions: cmds.actions, + getStatusText: function() { + if (util.currentMode == "insert") + return "INSERT"; + if (util.onVisualMode) + return (util.onVisualLineMode ? "VISUAL LINE " : "VISUAL ") + cmds.inputBuffer.status; + return cmds.inputBuffer.status; + } +}; + + +exports.onCursorMove = function(e) { + cmds.onCursorMove(e.editor, e); + exports.onCursorMove.scheduled = false; +}; + +}); diff --git a/lib/ace/keyboard/vim/commands.js b/lib/ace/keyboard/vim/commands.js new file mode 100644 index 0000000000..a9b24aa35e --- /dev/null +++ b/lib/ace/keyboard/vim/commands.js @@ -0,0 +1,561 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +"never use strict"; + +var util = require("./maps/util"); +var motions = require("./maps/motions"); +var operators = require("./maps/operators"); +var alias = require("./maps/aliases"); +var registers = require("./registers"); + +var NUMBER = 1; +var OPERATOR = 2; +var MOTION = 3; +var ACTION = 4; +var HMARGIN = 8; // Minimum amount of line separation between margins; + +var repeat = function repeat(fn, count, args) { + while (0 < count--) + fn.apply(this, args); +}; + +var ensureScrollMargin = function(editor) { + var renderer = editor.renderer; + var pos = renderer.$cursorLayer.getPixelPosition(); + + var top = pos.top; + + var margin = HMARGIN * renderer.layerConfig.lineHeight; + if (2 * margin > renderer.$size.scrollerHeight) + margin = renderer.$size.scrollerHeight / 2; + + if (renderer.scrollTop > top - margin) { + renderer.session.setScrollTop(top - margin); + } + + if (renderer.scrollTop + renderer.$size.scrollerHeight < top + margin + renderer.lineHeight) { + renderer.session.setScrollTop(top + margin + renderer.lineHeight - renderer.$size.scrollerHeight); + } +}; + +var actions = exports.actions = { + "z": { + param: true, + fn: function(editor, range, count, param) { + switch (param) { + case "z": + editor.renderer.alignCursor(null, 0.5); + break; + case "t": + editor.renderer.alignCursor(null, 0); + break; + case "b": + editor.renderer.alignCursor(null, 1); + break; + } + } + }, + "r": { + param: true, + fn: function(editor, range, count, param) { + if (param && param.length) { + repeat(function() { editor.insert(param); }, count || 1); + editor.navigateLeft(); + } + } + }, + "R": { + fn: function(editor, range, count, param) { + util.insertMode(editor); + editor.setOverwrite(true); + } + }, + "~": { + fn: function(editor, range, count) { + repeat(function() { + var range = editor.selection.getRange(); + if (range.isEmpty()) + range.end.column++; + var text = editor.session.getTextRange(range); + var toggled = text.toUpperCase(); + if (toggled == text) + editor.navigateRight(); + else + editor.session.replace(range, toggled); + }, count || 1); + } + }, + "*": { + fn: function(editor, range, count, param) { + editor.selection.selectWord(); + editor.findNext(); + ensureScrollMargin(editor); + var r = editor.selection.getRange(); + editor.selection.setSelectionRange(r, true); + } + }, + "#": { + fn: function(editor, range, count, param) { + editor.selection.selectWord(); + editor.findPrevious(); + ensureScrollMargin(editor); + var r = editor.selection.getRange(); + editor.selection.setSelectionRange(r, true); + } + }, + "n": { + fn: function(editor, range, count, param) { + var options = editor.getLastSearchOptions(); + options.backwards = false; + + editor.selection.moveCursorRight(); + editor.selection.clearSelection(); + editor.findNext(options); + + ensureScrollMargin(editor); + var r = editor.selection.getRange(); + r.end.row = r.start.row; + r.end.column = r.start.column; + editor.selection.setSelectionRange(r, true); + } + }, + "N": { + fn: function(editor, range, count, param) { + var options = editor.getLastSearchOptions(); + options.backwards = true; + + editor.findPrevious(options); + ensureScrollMargin(editor); + var r = editor.selection.getRange(); + r.end.row = r.start.row; + r.end.column = r.start.column; + editor.selection.setSelectionRange(r, true); + } + }, + "v": { + fn: function(editor, range, count, param) { + editor.selection.selectRight(); + util.visualMode(editor, false); + }, + acceptsMotion: true + }, + "V": { + fn: function(editor, range, count, param) { + //editor.selection.selectLine(); + //editor.selection.selectLeft(); + var row = editor.getCursorPosition().row; + editor.selection.clearSelection(); + editor.selection.moveCursorTo(row, 0); + editor.selection.selectLineEnd(); + editor.selection.visualLineStart = row; + + util.visualMode(editor, true); + }, + acceptsMotion: true + }, + "Y": { + fn: function(editor, range, count, param) { + util.copyLine(editor); + } + }, + "p": { + fn: function(editor, range, count, param) { + var defaultReg = registers._default; + + editor.setOverwrite(false); + if (defaultReg.isLine) { + var pos = editor.getCursorPosition(); + var lines = defaultReg.text.split("\n"); + editor.session.getDocument().insertLines(pos.row + 1, lines); + editor.moveCursorTo(pos.row + 1, 0); + } + else { + editor.navigateRight(); + editor.insert(defaultReg.text); + editor.navigateLeft(); + } + editor.setOverwrite(true); + editor.selection.clearSelection(); + } + }, + "P": { + fn: function(editor, range, count, param) { + var defaultReg = registers._default; + editor.setOverwrite(false); + + if (defaultReg.isLine) { + var pos = editor.getCursorPosition(); + var lines = defaultReg.text.split("\n"); + editor.session.getDocument().insertLines(pos.row, lines); + editor.moveCursorTo(pos.row, 0); + } + else { + editor.insert(defaultReg.text); + } + editor.setOverwrite(true); + editor.selection.clearSelection(); + } + }, + "J": { + fn: function(editor, range, count, param) { + var session = editor.session; + range = editor.getSelectionRange(); + var pos = {row: range.start.row, column: range.start.column}; + count = count || range.end.row - range.start.row; + var maxRow = Math.min(pos.row + (count || 1), session.getLength() - 1); + + range.start.column = session.getLine(pos.row).length; + range.end.column = session.getLine(maxRow).length; + range.end.row = maxRow; + + var text = ""; + for (var i = pos.row; i < maxRow; i++) { + var nextLine = session.getLine(i + 1); + text += " " + /^\s*(.*)$/.exec(nextLine)[1] || ""; + } + + session.replace(range, text); + editor.moveCursorTo(pos.row, pos.column); + } + }, + "u": { + fn: function(editor, range, count, param) { + count = parseInt(count || 1, 10); + for (var i = 0; i < count; i++) { + editor.undo(); + } + editor.selection.clearSelection(); + } + }, + "ctrl-r": { + fn: function(editor, range, count, param) { + count = parseInt(count || 1, 10); + for (var i = 0; i < count; i++) { + editor.redo(); + } + editor.selection.clearSelection(); + } + }, + ":": { + fn: function(editor, range, count, param) { + // not implemented + } + }, + "/": { + fn: function(editor, range, count, param) { + // not implemented + } + }, + "?": { + fn: function(editor, range, count, param) { + // not implemented + } + }, + ".": { + fn: function(editor, range, count, param) { + util.onInsertReplaySequence = inputBuffer.lastInsertCommands; + var previous = inputBuffer.previous; + if (previous) // If there is a previous action + inputBuffer.exec(editor, previous.action, previous.param); + } + } +}; + +var inputBuffer = exports.inputBuffer = { + accepting: [NUMBER, OPERATOR, MOTION, ACTION], + currentCmd: null, + //currentMode: 0, + currentCount: "", + status: "", + + // Types + operator: null, + motion: null, + + lastInsertCommands: [], + + push: function(editor, ch, keyId) { + this.idle = false; + var wObj = this.waitingForParam; + if (wObj) { + this.exec(editor, wObj, ch); + } + // If input is a number (that doesn't start with 0) + else if (!(ch === "0" && !this.currentCount.length) && + (ch.match(/^\d+$/) && this.isAccepting(NUMBER))) { + // Assuming that ch is always of type String, and not Number + this.currentCount += ch; + this.currentCmd = NUMBER; + this.accepting = [NUMBER, OPERATOR, MOTION, ACTION]; + } + else if (!this.operator && this.isAccepting(OPERATOR) && operators[ch]) { + this.operator = { + ch: ch, + count: this.getCount() + }; + this.currentCmd = OPERATOR; + this.accepting = [NUMBER, MOTION, ACTION]; + this.exec(editor, { operator: this.operator }); + } + else if (motions[ch] && this.isAccepting(MOTION)) { + this.currentCmd = MOTION; + + var ctx = { + operator: this.operator, + motion: { + ch: ch, + count: this.getCount() + } + }; + + if (motions[ch].param) + this.waitForParam(ctx); + else + this.exec(editor, ctx); + } + else if (alias[ch] && this.isAccepting(MOTION)) { + alias[ch].operator.count = this.getCount(); + this.exec(editor, alias[ch]); + } + else if (actions[ch] && this.isAccepting(ACTION)) { + var actionObj = { + action: { + fn: actions[ch].fn, + count: this.getCount() + } + }; + + if (actions[ch].param) { + this.waitForParam(actionObj); + } + else { + this.exec(editor, actionObj); + } + + if (actions[ch].acceptsMotion) + this.idle = false; + } + else if (this.operator) { + this.exec(editor, { operator: this.operator }, ch); + } + else { + this.reset(); + } + + if (this.waitingForParam || this.motion || this.operator) { + this.status += ch; + } else if (this.currentCount) { + this.status = this.currentCount; + } else if (this.status) { + this.status = ""; + } else { + return; + } + editor._emit("changeStatus"); + }, + + waitForParam: function(cmd) { + this.waitingForParam = cmd; + }, + + getCount: function() { + var count = this.currentCount; + this.currentCount = ""; + return count && parseInt(count, 10); + }, + + exec: function(editor, action, param) { + var m = action.motion; + var o = action.operator; + var a = action.action; + + if (!param) + param = action.param; + + if (o) { + this.previous = { + action: action, + param: param + }; + } + + if (o && !editor.selection.isEmpty()) { + if (operators[o.ch].selFn) { + operators[o.ch].selFn(editor, editor.getSelectionRange(), o.count, param); + this.reset(); + } + return; + } + + // There is an operator, but no motion or action. We try to pass the + // current ch to the operator to see if it responds to it (an example + // of this is the 'dd' operator). + else if (!m && !a && o && param) { + operators[o.ch].fn(editor, null, o.count, param); + this.reset(); + } + else if (m) { + var run = function(fn) { + if (fn && typeof fn === "function") { // There should always be a motion + if (m.count && !motionObj.handlesCount) + repeat(fn, m.count, [editor, null, m.count, param]); + else + fn(editor, null, m.count, param); + } + }; + + var motionObj = motions[m.ch]; + var selectable = motionObj.sel; + + if (!o) { + if ((util.onVisualMode || util.onVisualLineMode) && selectable) + run(motionObj.sel); + else + run(motionObj.nav); + } + else if (selectable) { + repeat(function() { + run(motionObj.sel); + operators[o.ch].fn(editor, editor.getSelectionRange(), o.count, param); + }, o.count || 1); + } + this.reset(); + } + else if (a) { + a.fn(editor, editor.getSelectionRange(), a.count, param); + this.reset(); + } + handleCursorMove(editor); + }, + + isAccepting: function(type) { + return this.accepting.indexOf(type) !== -1; + }, + + reset: function() { + this.operator = null; + this.motion = null; + this.currentCount = ""; + this.status = ""; + this.accepting = [NUMBER, OPERATOR, MOTION, ACTION]; + this.idle = true; + this.waitingForParam = null; + } +}; + +function setPreviousCommand(fn) { + inputBuffer.previous = { action: { action: { fn: fn } } }; +} + +exports.coreCommands = { + start: { + exec: function start(editor) { + util.insertMode(editor); + setPreviousCommand(start); + } + }, + startBeginning: { + exec: function startBeginning(editor) { + editor.navigateLineStart(); + util.insertMode(editor); + setPreviousCommand(startBeginning); + } + }, + // Stop Insert mode as soon as possible. Works like typing in + // insert mode. + stop: { + exec: function stop(editor) { + inputBuffer.reset(); + util.onVisualMode = false; + util.onVisualLineMode = false; + inputBuffer.lastInsertCommands = util.normalMode(editor); + } + }, + append: { + exec: function append(editor) { + var pos = editor.getCursorPosition(); + var lineLen = editor.session.getLine(pos.row).length; + if (lineLen) + editor.navigateRight(); + util.insertMode(editor); + setPreviousCommand(append); + } + }, + appendEnd: { + exec: function appendEnd(editor) { + editor.navigateLineEnd(); + util.insertMode(editor); + setPreviousCommand(appendEnd); + } + } +}; + +var handleCursorMove = exports.onCursorMove = function(editor, e) { + if (util.currentMode === 'insert' || handleCursorMove.running) + return; + else if(!editor.selection.isEmpty()) { + handleCursorMove.running = true; + if (util.onVisualLineMode) { + var originRow = editor.selection.visualLineStart; + var cursorRow = editor.getCursorPosition().row; + if(originRow <= cursorRow) { + var endLine = editor.session.getLine(cursorRow); + editor.selection.clearSelection(); + editor.selection.moveCursorTo(originRow, 0); + editor.selection.selectTo(cursorRow, endLine.length); + } else { + var endLine = editor.session.getLine(originRow); + editor.selection.clearSelection(); + editor.selection.moveCursorTo(originRow, endLine.length); + editor.selection.selectTo(cursorRow, 0); + } + } + handleCursorMove.running = false; + return; + } + else { + if (e && (util.onVisualLineMode || util.onVisualMode)) { + editor.selection.clearSelection(); + util.normalMode(editor); + } + + handleCursorMove.running = true; + var pos = editor.getCursorPosition(); + var lineLen = editor.session.getLine(pos.row).length; + + if (lineLen && pos.column === lineLen) + editor.navigateLeft(); + handleCursorMove.running = false; + } +}; +}); diff --git a/lib/ace/keyboard/vim/maps/aliases.js b/lib/ace/keyboard/vim/maps/aliases.js new file mode 100644 index 0000000000..1a5f32f7d8 --- /dev/null +++ b/lib/ace/keyboard/vim/maps/aliases.js @@ -0,0 +1,94 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +"use strict" + +define(function(require, exports, module) { +module.exports = { + "x": { + operator: { + ch: "d", + count: 1 + }, + motion: { + ch: "l", + count: 1 + } + }, + "X": { + operator: { + ch: "d", + count: 1 + }, + motion: { + ch: "h", + count: 1 + } + }, + "D": { + operator: { + ch: "d", + count: 1 + }, + motion: { + ch: "$", + count: 1 + } + }, + "C": { + operator: { + ch: "c", + count: 1 + }, + motion: { + ch: "$", + count: 1 + } + }, + "s": { + operator: { + ch: "c", + count: 1 + }, + motion: { + ch: "l", + count: 1 + } + }, + "S": { + operator: { + ch: "c", + count: 1 + }, + param: "c" + } +}; +}); + diff --git a/lib/ace/keyboard/vim/maps/motions.js b/lib/ace/keyboard/vim/maps/motions.js new file mode 100644 index 0000000000..036930ec91 --- /dev/null +++ b/lib/ace/keyboard/vim/maps/motions.js @@ -0,0 +1,593 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + + +define(function(require, exports, module) { +"use strict"; + +var util = require("./util"); + +var keepScrollPosition = function(editor, fn) { + var scrollTopRow = editor.renderer.getScrollTopRow(); + var initialRow = editor.getCursorPosition().row; + var diff = initialRow - scrollTopRow; + fn && fn.call(editor); + editor.renderer.scrollToRow(editor.getCursorPosition().row - diff); +}; + +function Motion(m) { + if (typeof m == "function") { + var getPos = m; + m = this; + } else { + var getPos = m.getPos; + } + m.nav = function(editor, range, count, param) { + var a = getPos(editor, range, count, param, false); + if (!a) + return; + editor.clearSelection(); + editor.moveCursorTo(a.row, a.column); + }; + m.sel = function(editor, range, count, param) { + var a = getPos(editor, range, count, param, true); + if (!a) + return; + editor.selection.selectTo(a.row, a.column); + }; + return m; +} + +var nonWordRe = /[\s.\/\\()\"'-:,.;<>~!@#$%^&*|+=\[\]{}`~?]/; +var wordSeparatorRe = /[.\/\\()\"'-:,.;<>~!@#$%^&*|+=\[\]{}`~?]/; +var whiteRe = /\s/; +var StringStream = function(editor, cursor) { + var sel = editor.selection; + this.range = sel.getRange(); + cursor = cursor || sel.selectionLead; + this.row = cursor.row; + this.col = cursor.column; + var line = editor.session.getLine(this.row); + var maxRow = editor.session.getLength(); + this.ch = line[this.col] || '\n'; + this.skippedLines = 0; + + this.next = function() { + this.ch = line[++this.col] || this.handleNewLine(1); + //this.debug() + return this.ch; + }; + this.prev = function() { + this.ch = line[--this.col] || this.handleNewLine(-1); + //this.debug() + return this.ch; + }; + this.peek = function(dir) { + var ch = line[this.col + dir]; + if (ch) + return ch; + if (dir == -1) + return '\n'; + if (this.col == line.length - 1) + return '\n'; + return editor.session.getLine(this.row + 1)[0] || '\n'; + }; + + this.handleNewLine = function(dir) { + if (dir == 1){ + if (this.col == line.length) + return '\n'; + if (this.row == maxRow - 1) + return ''; + this.col = 0; + this.row ++; + line = editor.session.getLine(this.row); + this.skippedLines++; + return line[0] || '\n'; + } + if (dir == -1) { + if (this.row === 0) + return ''; + this.row --; + line = editor.session.getLine(this.row); + this.col = line.length; + this.skippedLines--; + return '\n'; + } + }; + this.debug = function() { + console.log(line.substring(0, this.col)+'|'+this.ch+'\''+this.col+'\''+line.substr(this.col+1)); + }; +}; + +var Search = require("../../../search").Search; +var search = new Search(); + +function find(editor, needle, dir) { + search.$options.needle = needle; + search.$options.backwards = dir == -1; + return search.find(editor.session); +} + +var Range = require("../../../range").Range; + +module.exports = { + "w": new Motion(function(editor) { + var str = new StringStream(editor); + + if (str.ch && wordSeparatorRe.test(str.ch)) { + while (str.ch && wordSeparatorRe.test(str.ch)) + str.next(); + } else { + while (str.ch && !nonWordRe.test(str.ch)) + str.next(); + } + while (str.ch && whiteRe.test(str.ch) && str.skippedLines < 2) + str.next(); + + str.skippedLines == 2 && str.prev(); + return {column: str.col, row: str.row}; + }), + "W": new Motion(function(editor) { + var str = new StringStream(editor); + while(str.ch && !(whiteRe.test(str.ch) && !whiteRe.test(str.peek(1))) && str.skippedLines < 2) + str.next(); + if (str.skippedLines == 2) + str.prev(); + else + str.next(); + + return {column: str.col, row: str.row}; + }), + "b": new Motion(function(editor) { + var str = new StringStream(editor); + + str.prev(); + while (str.ch && whiteRe.test(str.ch) && str.skippedLines > -2) + str.prev(); + + if (str.ch && wordSeparatorRe.test(str.ch)) { + while (str.ch && wordSeparatorRe.test(str.ch)) + str.prev(); + } else { + while (str.ch && !nonWordRe.test(str.ch)) + str.prev(); + } + str.ch && str.next(); + return {column: str.col, row: str.row}; + }), + "B": new Motion(function(editor) { + var str = new StringStream(editor); + str.prev(); + while(str.ch && !(!whiteRe.test(str.ch) && whiteRe.test(str.peek(-1))) && str.skippedLines > -2) + str.prev(); + + if (str.skippedLines == -2) + str.next(); + + return {column: str.col, row: str.row}; + }), + "e": new Motion(function(editor) { + var str = new StringStream(editor); + + str.next(); + while (str.ch && whiteRe.test(str.ch)) + str.next(); + + if (str.ch && wordSeparatorRe.test(str.ch)) { + while (str.ch && wordSeparatorRe.test(str.ch)) + str.next(); + } else { + while (str.ch && !nonWordRe.test(str.ch)) + str.next(); + } + str.ch && str.prev(); + return {column: str.col, row: str.row}; + }), + "E": new Motion(function(editor) { + var str = new StringStream(editor); + str.next(); + while(str.ch && !(!whiteRe.test(str.ch) && whiteRe.test(str.peek(1)))) + str.next(); + + return {column: str.col, row: str.row}; + }), + + "l": { + nav: function(editor) { + editor.navigateRight(); + }, + sel: function(editor) { + var pos = editor.getCursorPosition(); + var col = pos.column; + var lineLen = editor.session.getLine(pos.row).length; + + // Solving the behavior at the end of the line due to the + // different 0 index-based colum positions in ACE. + if (lineLen && col !== lineLen) //In selection mode you can select the newline + editor.selection.selectRight(); + } + }, + "h": { + nav: function(editor) { + var pos = editor.getCursorPosition(); + if (pos.column > 0) + editor.navigateLeft(); + }, + sel: function(editor) { + var pos = editor.getCursorPosition(); + if (pos.column > 0) + editor.selection.selectLeft(); + } + }, + "H": { + nav: function(editor) { + var row = editor.renderer.getScrollTopRow(); + editor.moveCursorTo(row); + }, + sel: function(editor) { + var row = editor.renderer.getScrollTopRow(); + editor.selection.selectTo(row); + } + }, + "M": { + nav: function(editor) { + var topRow = editor.renderer.getScrollTopRow(); + var bottomRow = editor.renderer.getScrollBottomRow(); + var row = topRow + ((bottomRow - topRow) / 2); + editor.moveCursorTo(row); + }, + sel: function(editor) { + var topRow = editor.renderer.getScrollTopRow(); + var bottomRow = editor.renderer.getScrollBottomRow(); + var row = topRow + ((bottomRow - topRow) / 2); + editor.selection.selectTo(row); + } + }, + "L": { + nav: function(editor) { + var row = editor.renderer.getScrollBottomRow(); + editor.moveCursorTo(row); + }, + sel: function(editor) { + var row = editor.renderer.getScrollBottomRow(); + editor.selection.selectTo(row); + } + }, + "k": { + nav: function(editor) { + editor.navigateUp(); + }, + sel: function(editor) { + editor.selection.selectUp(); + } + }, + "j": { + nav: function(editor) { + editor.navigateDown(); + }, + sel: function(editor) { + editor.selection.selectDown(); + } + }, + + "i": { + param: true, + sel: function(editor, range, count, param) { + switch (param) { + case "w": + editor.selection.selectWord(); + break; + case "W": + editor.selection.selectAWord(); + break; + case "(": + case "{": + case "[": + var cursor = editor.getCursorPosition(); + var end = editor.session.$findClosingBracket(param, cursor, /paren/); + if (!end) + return; + var start = editor.session.$findOpeningBracket(editor.session.$brackets[param], cursor, /paren/); + if (!start) + return; + start.column ++; + editor.selection.setSelectionRange(Range.fromPoints(start, end)); + break; + case "'": + case '"': + case "/": + var end = find(editor, param, 1); + if (!end) + return; + var start = find(editor, param, -1); + if (!start) + return; + editor.selection.setSelectionRange(Range.fromPoints(start.end, end.start)); + break; + } + } + }, + "a": { + param: true, + sel: function(editor, range, count, param) { + switch (param) { + case "w": + editor.selection.selectAWord(); + break; + case "W": + editor.selection.selectAWord(); + break; + case "(": + case "{": + case "[": + var cursor = editor.getCursorPosition(); + var end = editor.session.$findClosingBracket(param, cursor, /paren/); + if (!end) + return; + var start = editor.session.$findOpeningBracket(editor.session.$brackets[param], cursor, /paren/); + if (!start) + return; + end.column ++; + editor.selection.setSelectionRange(Range.fromPoints(start, end)); + break; + case "'": + case "\"": + case "/": + var end = find(editor, param, 1); + if (!end) + return; + var start = find(editor, param, -1); + if (!start) + return; + end.column ++; + editor.selection.setSelectionRange(Range.fromPoints(start.start, end.end)); + break; + } + } + }, + + "f": new Motion({ + param: true, + handlesCount: true, + getPos: function(editor, range, count, param, isSel) { + var cursor = editor.getCursorPosition(); + var column = util.getRightNthChar(editor, cursor, param, count || 1); + + if (typeof column === "number") { + cursor.column += column + (isSel ? 2 : 1); + return cursor; + } + } + }), + "F": new Motion({ + param: true, + handlesCount: true, + getPos: function(editor, range, count, param, isSel) { + var cursor = editor.getCursorPosition(); + var column = util.getLeftNthChar(editor, cursor, param, count || 1); + + if (typeof column === "number") { + cursor.column -= column + 1; + return cursor; + } + } + }), + "t": new Motion({ + param: true, + handlesCount: true, + getPos: function(editor, range, count, param, isSel) { + var cursor = editor.getCursorPosition(); + var column = util.getRightNthChar(editor, cursor, param, count || 1); + + if (typeof column === "number") { + cursor.column += column + (isSel ? 1 : 0); + return cursor; + } + } + }), + "T": new Motion({ + param: true, + handlesCount: true, + getPos: function(editor, range, count, param, isSel) { + var cursor = editor.getCursorPosition(); + var column = util.getLeftNthChar(editor, cursor, param, count || 1); + + if (typeof column === "number") { + cursor.column -= column; + return cursor; + } + } + }), + + "^": { + nav: function(editor) { + editor.navigateLineStart(); + }, + sel: function(editor) { + editor.selection.selectLineStart(); + } + }, + "$": { + nav: function(editor) { + editor.navigateLineEnd(); + }, + sel: function(editor) { + editor.selection.selectLineEnd(); + } + }, + "0": new Motion(function(ed) { + return {row: ed.selection.lead.row, column: 0}; + }), + "G": { + nav: function(editor, range, count, param) { + if (!count && count !== 0) { // Stupid JS + count = editor.session.getLength(); + } + editor.gotoLine(count); + }, + sel: function(editor, range, count, param) { + if (!count && count !== 0) { // Stupid JS + count = editor.session.getLength(); + } + editor.selection.selectTo(count, 0); + } + }, + "g": { + param: true, + nav: function(editor, range, count, param) { + switch(param) { + case "m": + console.log("Middle line"); + break; + case "e": + console.log("End of prev word"); + break; + case "g": + editor.gotoLine(count || 0); + case "u": + editor.gotoLine(count || 0); + case "U": + editor.gotoLine(count || 0); + } + }, + sel: function(editor, range, count, param) { + switch(param) { + case "m": + console.log("Middle line"); + break; + case "e": + console.log("End of prev word"); + break; + case "g": + editor.selection.selectTo(count || 0, 0); + } + } + }, + "o": { + nav: function(editor, range, count, param) { + count = count || 1; + var content = ""; + while (0 < count--) + content += "\n"; + + if (content.length) { + editor.navigateLineEnd() + editor.insert(content); + util.insertMode(editor); + } + } + }, + "O": { + nav: function(editor, range, count, param) { + var row = editor.getCursorPosition().row; + count = count || 1; + var content = ""; + while (0 < count--) + content += "\n"; + + if (content.length) { + if(row > 0) { + editor.navigateUp(); + editor.navigateLineEnd() + editor.insert(content); + } else { + editor.session.insert({row: 0, column: 0}, content); + editor.navigateUp(); + } + util.insertMode(editor); + } + } + }, + "%": new Motion(function(editor){ + var brRe = /[\[\]{}()]/g; + var cursor = editor.getCursorPosition(); + var ch = editor.session.getLine(cursor.row)[cursor.column]; + if (!brRe.test(ch)) { + var range = find(editor, brRe); + if (!range) + return; + cursor = range.start; + } + var match = editor.session.findMatchingBracket({ + row: cursor.row, + column: cursor.column + 1 + }); + + return match; + }), + "{": new Motion(function(ed) { + var session = ed.session; + var row = session.selection.lead.row; + while(row > 0 && !/\S/.test(session.getLine(row))) + row--; + while(/\S/.test(session.getLine(row))) + row--; + return {column: 0, row: row}; + }), + "}": new Motion(function(ed) { + var session = ed.session; + var l = session.getLength(); + var row = session.selection.lead.row; + while(row < l && !/\S/.test(session.getLine(row))) + row++; + while(/\S/.test(session.getLine(row))) + row++; + return {column: 0, row: row}; + }), + "ctrl-d": { + nav: function(editor, range, count, param) { + editor.selection.clearSelection(); + keepScrollPosition(editor, editor.gotoPageDown); + }, + sel: function(editor, range, count, param) { + keepScrollPosition(editor, editor.selectPageDown); + } + }, + "ctrl-u": { + nav: function(editor, range, count, param) { + editor.selection.clearSelection(); + keepScrollPosition(editor, editor.gotoPageUp); + + }, + sel: function(editor, range, count, param) { + keepScrollPosition(editor, editor.selectPageUp); + } + } +}; + +module.exports.backspace = module.exports.left = module.exports.h; +module.exports.right = module.exports.l; +module.exports.up = module.exports.k; +module.exports.down = module.exports.j; +module.exports.pagedown = module.exports["ctrl-d"]; +module.exports.pageup = module.exports["ctrl-u"]; + +}); diff --git a/lib/ace/keyboard/vim/maps/operators.js b/lib/ace/keyboard/vim/maps/operators.js new file mode 100644 index 0000000000..702abc6ebc --- /dev/null +++ b/lib/ace/keyboard/vim/maps/operators.js @@ -0,0 +1,196 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +"never use strict"; + +var util = require("./util"); +var registers = require("../registers"); + +module.exports = { + "d": { + selFn: function(editor, range, count, param) { + registers._default.text = editor.getCopyText(); + registers._default.isLine = util.onVisualLineMode; + if(util.onVisualLineMode) + editor.removeLines(); + else + editor.session.remove(range); + util.normalMode(editor); + }, + fn: function(editor, range, count, param) { + count = count || 1; + switch (param) { + case "d": + registers._default.text = ""; + registers._default.isLine = true; + for (var i = 0; i < count; i++) { + editor.selection.selectLine(); + registers._default.text += editor.getCopyText(); + var selRange = editor.getSelectionRange(); + // check if end of the document was reached + if (!selRange.isMultiLine()) { + lastLineReached = true + var row = selRange.start.row - 1; + var col = editor.session.getLine(row).length + selRange.setStart(row, col); + editor.session.remove(selRange); + editor.selection.clearSelection(); + break; + } + editor.session.remove(selRange); + editor.selection.clearSelection(); + } + registers._default.text = registers._default.text.replace(/\n$/, ""); + break; + default: + if (range) { + editor.selection.setSelectionRange(range); + registers._default.text = editor.getCopyText(); + registers._default.isLine = false; + editor.session.remove(range); + editor.selection.clearSelection(); + } + } + } + }, + "c": { + selFn: function(editor, range, count, param) { + editor.session.remove(range); + util.insertMode(editor); + }, + fn: function(editor, range, count, param) { + count = count || 1; + switch (param) { + case "c": + for (var i = 0; i < count; i++) { + editor.removeLines(); + util.insertMode(editor); + } + + break; + default: + if (range) { + + // range.end.column ++; + editor.session.remove(range); + util.insertMode(editor); + } + } + } + }, + "y": { + selFn: function(editor, range, count, param) { + registers._default.text = editor.getCopyText(); + registers._default.isLine = util.onVisualLineMode; + editor.selection.clearSelection(); + util.normalMode(editor); + }, + fn: function(editor, range, count, param) { + count = count || 1; + switch (param) { + case "y": + var pos = editor.getCursorPosition(); + editor.selection.selectLine(); + for (var i = 0; i < count - 1; i++) { + editor.selection.moveCursorDown(); + } + registers._default.text = editor.getCopyText().replace(/\n$/, ""); + editor.selection.clearSelection(); + registers._default.isLine = true; + editor.moveCursorToPosition(pos); + break; + default: + if (range) { + var pos = editor.getCursorPosition(); + editor.selection.setSelectionRange(range); + registers._default.text = editor.getCopyText(); + registers._default.isLine = false; + editor.selection.clearSelection(); + editor.moveCursorTo(pos.row, pos.column); + } + } + } + }, + ">": { + selFn: function(editor, range, count, param) { + count = count || 1; + for (var i = 0; i < count; i++) { + editor.indent(); + } + util.normalMode(editor); + }, + fn: function(editor, range, count, param) { + count = parseInt(count || 1, 10); + switch (param) { + case ">": + var pos = editor.getCursorPosition(); + editor.selection.selectLine(); + for (var i = 0; i < count - 1; i++) { + editor.selection.moveCursorDown(); + } + editor.indent(); + editor.selection.clearSelection(); + editor.moveCursorToPosition(pos); + editor.navigateLineEnd(); + editor.navigateLineStart(); + break; + } + } + }, + "<": { + selFn: function(editor, range, count, param) { + count = count || 1; + for (var i = 0; i < count; i++) { + editor.blockOutdent(); + } + util.normalMode(editor); + }, + fn: function(editor, range, count, param) { + count = count || 1; + switch (param) { + case "<": + var pos = editor.getCursorPosition(); + editor.selection.selectLine(); + for (var i = 0; i < count - 1; i++) { + editor.selection.moveCursorDown(); + } + editor.blockOutdent(); + editor.selection.clearSelection(); + editor.moveCursorToPosition(pos); + editor.navigateLineEnd(); + editor.navigateLineStart(); + break; + } + } + } +}; +}); diff --git a/lib/ace/keyboard/vim/maps/util.js b/lib/ace/keyboard/vim/maps/util.js new file mode 100644 index 0000000000..af0e07c70f --- /dev/null +++ b/lib/ace/keyboard/vim/maps/util.js @@ -0,0 +1,134 @@ +define(function(require, exports, module) { +var registers = require("../registers"); + +var dom = require("../../../lib/dom"); +dom.importCssString('.insert-mode .ace_cursor{\ + border-left: 2px solid #333333;\ +}\ +.ace_dark.insert-mode .ace_cursor{\ + border-left: 2px solid #eeeeee;\ +}\ +.normal-mode .ace_cursor{\ + border: 0!important;\ + background-color: red;\ + opacity: 0.5;\ +}', 'vimMode'); + +module.exports = { + onVisualMode: false, + onVisualLineMode: false, + currentMode: 'normal', + noMode: function(editor) { + editor.unsetStyle('insert-mode'); + editor.unsetStyle('normal-mode'); + if (editor.commands.recording) + editor.commands.toggleRecording(editor); + editor.setOverwrite(false); + }, + insertMode: function(editor) { + this.currentMode = 'insert'; + // Switch editor to insert mode + editor.setStyle('insert-mode'); + editor.unsetStyle('normal-mode'); + + editor.setOverwrite(false); + editor.keyBinding.$data.buffer = ""; + editor.keyBinding.$data.state = "insertMode"; + this.onVisualMode = false; + this.onVisualLineMode = false; + if(this.onInsertReplaySequence) { + // Ok, we're apparently replaying ("."), so let's do it + editor.commands.macro = this.onInsertReplaySequence; + editor.commands.replay(editor); + this.onInsertReplaySequence = null; + this.normalMode(editor); + } else { + editor._emit("changeStatus"); + // Record any movements, insertions in insert mode + if(!editor.commands.recording) + editor.commands.toggleRecording(editor); + } + }, + normalMode: function(editor) { + // Switch editor to normal mode + this.currentMode = 'normal'; + + editor.unsetStyle('insert-mode'); + editor.setStyle('normal-mode'); + editor.clearSelection(); + + var pos; + if (!editor.getOverwrite()) { + pos = editor.getCursorPosition(); + if (pos.column > 0) + editor.navigateLeft(); + } + + editor.setOverwrite(true); + editor.keyBinding.$data.buffer = ""; + editor.keyBinding.$data.state = "start"; + this.onVisualMode = false; + this.onVisualLineMode = false; + editor._emit("changeStatus"); + // Save recorded keystrokes + if (editor.commands.recording) { + editor.commands.toggleRecording(editor); + return editor.commands.macro; + } + else { + return []; + } + }, + visualMode: function(editor, lineMode) { + if ( + (this.onVisualLineMode && lineMode) + || (this.onVisualMode && !lineMode) + ) { + this.normalMode(editor); + return; + } + + editor.setStyle('insert-mode'); + editor.unsetStyle('normal-mode'); + + editor._emit("changeStatus"); + if (lineMode) { + this.onVisualLineMode = true; + } else { + this.onVisualMode = true; + this.onVisualLineMode = false; + } + }, + getRightNthChar: function(editor, cursor, ch, n) { + var line = editor.getSession().getLine(cursor.row); + var matches = line.substr(cursor.column + 1).split(ch); + + return n < matches.length ? matches.slice(0, n).join(ch).length : null; + }, + getLeftNthChar: function(editor, cursor, ch, n) { + var line = editor.getSession().getLine(cursor.row); + var matches = line.substr(0, cursor.column).split(ch); + + return n < matches.length ? matches.slice(-1 * n).join(ch).length : null; + }, + toRealChar: function(ch) { + if (ch.length === 1) + return ch; + + if (/^shift-./.test(ch)) + return ch[ch.length - 1].toUpperCase(); + else + return ""; + }, + copyLine: function(editor) { + var pos = editor.getCursorPosition(); + editor.selection.clearSelection(); + editor.moveCursorTo(pos.row, pos.column); + editor.selection.selectLine(); + registers._default.isLine = true; + registers._default.text = editor.getCopyText().replace(/\n$/, ""); + editor.selection.clearSelection(); + editor.moveCursorTo(pos.row, pos.column); + } +}; +}); diff --git a/lib/ace/keyboard/vim/registers.js b/lib/ace/keyboard/vim/registers.js new file mode 100644 index 0000000000..ef929a3561 --- /dev/null +++ b/lib/ace/keyboard/vim/registers.js @@ -0,0 +1,42 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +"never use strict"; + +module.exports = { + _default: { + text: "", + isLine: false + } +}; + +}); diff --git a/lib/ace/layer/cursor.js b/lib/ace/layer/cursor.js new file mode 100644 index 0000000000..bd0219a4cc --- /dev/null +++ b/lib/ace/layer/cursor.js @@ -0,0 +1,217 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var dom = require("../lib/dom"); + +var Cursor = function(parentEl) { + this.element = dom.createElement("div"); + this.element.className = "ace_layer ace_cursor-layer"; + parentEl.appendChild(this.element); + + this.isVisible = false; + this.isBlinking = true; + this.blinkInterval = 1000; + this.smoothBlinking = false; + + this.cursors = []; + this.cursor = this.addCursor(); + dom.addCssClass(this.element, "ace_hidden-cursors"); +}; + +(function() { + + this.$padding = 0; + this.setPadding = function(padding) { + this.$padding = padding; + }; + + this.setSession = function(session) { + this.session = session; + }; + + this.setBlinking = function(blinking) { + if (blinking != this.isBlinking){ + this.isBlinking = blinking; + this.restartTimer(); + } + }; + + this.setBlinkInterval = function(blinkInterval) { + if (blinkInterval != this.blinkInterval){ + this.blinkInterval = blinkInterval; + this.restartTimer(); + } + }; + + this.setSmoothBlinking = function(smoothBlinking) { + if (smoothBlinking != this.smoothBlinking) { + this.smoothBlinking = smoothBlinking; + if (smoothBlinking) + dom.addCssClass(this.element, "ace_smooth-blinking"); + else + dom.removeCssClass(this.element, "ace_smooth-blinking"); + this.restartTimer(); + } + }; + + this.addCursor = function() { + var el = dom.createElement("div"); + el.className = "ace_cursor"; + this.element.appendChild(el); + this.cursors.push(el); + return el; + }; + + this.removeCursor = function() { + if (this.cursors.length > 1) { + var el = this.cursors.pop(); + el.parentNode.removeChild(el); + return el; + } + }; + + this.hideCursor = function() { + this.isVisible = false; + dom.addCssClass(this.element, "ace_hidden-cursors"); + this.restartTimer(); + }; + + this.showCursor = function() { + this.isVisible = true; + dom.removeCssClass(this.element, "ace_hidden-cursors"); + this.restartTimer(); + }; + + this.restartTimer = function() { + clearInterval(this.intervalId); + clearTimeout(this.timeoutId); + if (this.smoothBlinking) + dom.removeCssClass(this.element, "ace_smooth-blinking"); + for (var i = this.cursors.length; i--; ) + this.cursors[i].style.opacity = ""; + + if (!this.isBlinking || !this.blinkInterval || !this.isVisible) + return; + + if (this.smoothBlinking) + setTimeout(function(){ + dom.addCssClass(this.element, "ace_smooth-blinking"); + }.bind(this)); + + var blink = function(){ + this.timeoutId = setTimeout(function() { + for (var i = this.cursors.length; i--; ) { + this.cursors[i].style.opacity = 0; + } + }.bind(this), 0.6 * this.blinkInterval); + }.bind(this); + + this.intervalId = setInterval(function() { + for (var i = this.cursors.length; i--; ) { + this.cursors[i].style.opacity = ""; + } + blink(); + }.bind(this), this.blinkInterval); + + blink(); + }; + + this.getPixelPosition = function(position, onScreen) { + if (!this.config || !this.session) + return {left : 0, top : 0}; + + if (!position) + position = this.session.selection.getCursor(); + var pos = this.session.documentToScreenPosition(position); + var cursorLeft = this.$padding + pos.column * this.config.characterWidth; + var cursorTop = (pos.row - (onScreen ? this.config.firstRowScreen : 0)) * + this.config.lineHeight; + + return {left : cursorLeft, top : cursorTop}; + }; + + this.update = function(config) { + this.config = config; + + var selections = this.session.$selectionMarkers; + var i = 0, cursorIndex = 0; + + if (selections === undefined || selections.length === 0){ + selections = [{cursor: null}]; + } + + for (var i = selections.length; i--; ) { + var pixelPos = this.getPixelPosition(selections[i].cursor, true); + if ((pixelPos.top > config.height + config.offset || + pixelPos.top < -config.offset) && i > 1) { + continue; + } + + var style = (this.cursors[cursorIndex++] || this.addCursor()).style; + + style.left = pixelPos.left + "px"; + style.top = pixelPos.top + "px"; + style.width = config.characterWidth + "px"; + style.height = config.lineHeight + "px"; + } + while (this.cursors.length > cursorIndex) + this.removeCursor(); + + var overwrite = this.session.getOverwrite(); + this.$setOverwrite(overwrite); + + // cache for textarea and gutter highlight + this.$pixelPos = pixelPos; + this.restartTimer(); + }; + + this.$setOverwrite = function(overwrite) { + if (overwrite != this.overwrite) { + this.overwrite = overwrite; + if (overwrite) + dom.addCssClass(this.element, "ace_overwrite-cursors"); + else + dom.removeCssClass(this.element, "ace_overwrite-cursors"); + } + }; + + this.destroy = function() { + clearInterval(this.intervalId); + clearTimeout(this.timeoutId); + }; + +}).call(Cursor.prototype); + +exports.Cursor = Cursor; + +}); diff --git a/lib/ace/layer/gutter.js b/lib/ace/layer/gutter.js new file mode 100644 index 0000000000..99fec7b6ac --- /dev/null +++ b/lib/ace/layer/gutter.js @@ -0,0 +1,221 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var dom = require("../lib/dom"); +var oop = require("../lib/oop"); +var lang = require("../lib/lang"); +var EventEmitter = require("../lib/event_emitter").EventEmitter; + +var Gutter = function(parentEl) { + this.element = dom.createElement("div"); + this.element.className = "ace_layer ace_gutter-layer"; + parentEl.appendChild(this.element); + this.setShowFoldWidgets(this.$showFoldWidgets); + + this.gutterWidth = 0; + + this.$annotations = []; + this.$updateAnnotations = this.$updateAnnotations.bind(this); +}; + +(function() { + + oop.implement(this, EventEmitter); + + this.setSession = function(session) { + if (this.session) + this.session.removeEventListener("change", this.$updateAnnotations); + this.session = session; + session.on("change", this.$updateAnnotations); + }; + + this.addGutterDecoration = function(row, className){ + if (window.console) + console.warn && console.warn("deprecated use session.addGutterDecoration"); + this.session.addGutterDecoration(row, className); + }; + + this.removeGutterDecoration = function(row, className){ + if (window.console) + console.warn && console.warn("deprecated use session.removeGutterDecoration"); + this.session.removeGutterDecoration(row, className); + }; + + this.setAnnotations = function(annotations) { + // iterate over sparse array + this.$annotations = [] + var rowInfo, row; + for (var i = 0; i < annotations.length; i++) { + var annotation = annotations[i]; + var row = annotation.row; + var rowInfo = this.$annotations[row]; + if (!rowInfo) + rowInfo = this.$annotations[row] = {text: []}; + + var annoText = annotation.text; + annoText = annoText ? lang.escapeHTML(annoText) : annotation.html || ""; + + if (rowInfo.text.indexOf(annoText) === -1) + rowInfo.text.push(annoText); + + var type = annotation.type; + if (type == "error") + rowInfo.className = " ace_error"; + else if (type == "warning" && rowInfo.className != " ace_error") + rowInfo.className = " ace_warning"; + else if (type == "info" && (!rowInfo.className)) + rowInfo.className = " ace_info"; + } + }; + + this.$updateAnnotations = function (e) { + if (!this.$annotations.length) + return; + var delta = e.data; + var range = delta.range; + var firstRow = range.start.row; + var len = range.end.row - firstRow; + if (len === 0) { + // do nothing + } else if (delta.action == "removeText" || delta.action == "removeLines") { + this.$annotations.splice(firstRow, len + 1, null); + } else { + var args = Array(len + 1); + args.unshift(firstRow, 1); + this.$annotations.splice.apply(this.$annotations, args); + } + }; + + this.update = function(config) { + var emptyAnno = {className: ""}; + var html = []; + var i = config.firstRow; + var lastRow = config.lastRow; + var fold = this.session.getNextFoldLine(i); + var foldStart = fold ? fold.start.row : Infinity; + var foldWidgets = this.$showFoldWidgets && this.session.foldWidgets; + var breakpoints = this.session.$breakpoints; + var decorations = this.session.$decorations; + var lastLineNumber = 0; + + while (true) { + if(i > foldStart) { + i = fold.end.row + 1; + fold = this.session.getNextFoldLine(i, fold); + foldStart = fold ?fold.start.row :Infinity; + } + if(i > lastRow) + break; + + var annotation = this.$annotations[i] || emptyAnno; + html.push( + "
", + lastLineNumber = i + 1 + ); + + if (foldWidgets) { + var c = foldWidgets[i]; + // check if cached value is invalidated and we need to recompute + if (c == null) + c = foldWidgets[i] = this.session.getFoldWidget(i); + if (c) + html.push( + "" + ); + } + + html.push("
"); + + i++; + } + + this.element = dom.setInnerHtml(this.element, html.join("")); + this.element.style.height = config.minHeight + "px"; + + if (this.session.$useWrapMode) + lastLineNumber = this.session.getLength(); + + var gutterWidth = ("" + lastLineNumber).length * config.characterWidth; + var padding = this.$padding || this.$computePadding(); + gutterWidth += padding.left + padding.right; + if (gutterWidth !== this.gutterWidth) { + this.gutterWidth = gutterWidth; + this.element.style.width = Math.ceil(this.gutterWidth) + "px"; + this._emit("changeGutterWidth", gutterWidth); + } + }; + + this.$showFoldWidgets = true; + this.setShowFoldWidgets = function(show) { + if (show) + dom.addCssClass(this.element, "ace_folding-enabled"); + else + dom.removeCssClass(this.element, "ace_folding-enabled"); + + this.$showFoldWidgets = show; + this.$padding = null; + }; + + this.getShowFoldWidgets = function() { + return this.$showFoldWidgets; + }; + + this.$computePadding = function() { + if (!this.element.firstChild) + return {left: 0, right: 0}; + var style = dom.computedStyle(this.element.firstChild); + this.$padding = {} + this.$padding.left = parseInt(style.paddingLeft) + 1; + this.$padding.right = parseInt(style.paddingRight); + return this.$padding; + }; + + this.getRegion = function(point) { + var padding = this.$padding || this.$computePadding(); + var rect = this.element.getBoundingClientRect(); + if (point.x < padding.left + rect.left) + return "markers"; + if (this.$showFoldWidgets && point.x > rect.right - padding.right) + return "foldWidgets"; + }; + +}).call(Gutter.prototype); + +exports.Gutter = Gutter; + +}); diff --git a/lib/ace/layer/marker.js b/lib/ace/layer/marker.js new file mode 100644 index 0000000000..c68d3964f5 --- /dev/null +++ b/lib/ace/layer/marker.js @@ -0,0 +1,203 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var Range = require("../range").Range; +var dom = require("../lib/dom"); + +var Marker = function(parentEl) { + this.element = dom.createElement("div"); + this.element.className = "ace_layer ace_marker-layer"; + parentEl.appendChild(this.element); +}; + +(function() { + + this.$padding = 0; + + this.setPadding = function(padding) { + this.$padding = padding; + }; + this.setSession = function(session) { + this.session = session; + }; + + this.setMarkers = function(markers) { + this.markers = markers; + }; + + this.update = function(config) { + var config = config || this.config; + if (!config) + return; + + this.config = config; + + + var html = []; + for (var key in this.markers) { + var marker = this.markers[key]; + + if (!marker.range) { + marker.update(html, this, this.session, config); + continue; + } + + var range = marker.range.clipRows(config.firstRow, config.lastRow); + if (range.isEmpty()) continue; + + range = range.toScreenRange(this.session); + if (marker.renderer) { + var top = this.$getTop(range.start.row, config); + var left = this.$padding + range.start.column * config.characterWidth; + marker.renderer(html, range, left, top, config); + } else if (marker.type == "fullLine") { + this.drawFullLineMarker(html, range, marker.clazz, config); + } else if (range.isMultiLine()) { + if (marker.type == "text") + this.drawTextMarker(html, range, marker.clazz, config); + else + this.drawMultiLineMarker(html, range, marker.clazz, config); + } else { + this.drawSingleLineMarker(html, range, marker.clazz + " ace_start", config); + } + } + this.element = dom.setInnerHtml(this.element, html.join("")); + }; + + this.$getTop = function(row, layerConfig) { + return (row - layerConfig.firstRowScreen) * layerConfig.lineHeight; + }; + + // Draws a marker, which spans a range of text on multiple lines + this.drawTextMarker = function(stringBuilder, range, clazz, layerConfig) { + // selection start + var row = range.start.row; + + var lineRange = new Range( + row, range.start.column, + row, this.session.getScreenLastRowColumn(row) + ); + this.drawSingleLineMarker(stringBuilder, lineRange, clazz + " ace_start", layerConfig, 1, "text"); + + // selection end + row = range.end.row; + lineRange = new Range(row, 0, row, range.end.column); + this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 0, "text"); + + for (row = range.start.row + 1; row < range.end.row; row++) { + lineRange.start.row = row; + lineRange.end.row = row; + lineRange.end.column = this.session.getScreenLastRowColumn(row); + this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 1, "text"); + } + }; + + // Draws a multi line marker, where lines span the full width + this.drawMultiLineMarker = function(stringBuilder, range, clazz, config, type) { + // from selection start to the end of the line + var padding = this.$padding; + var height = config.lineHeight; + var top = this.$getTop(range.start.row, config); + var left = padding + range.start.column * config.characterWidth; + + stringBuilder.push( + "
" + ); + + // from start of the last line to the selection end + top = this.$getTop(range.end.row, config); + var width = range.end.column * config.characterWidth; + + stringBuilder.push( + "
" + ); + + // all the complete lines + height = (range.end.row - range.start.row - 1) * config.lineHeight; + if (height < 0) + return; + top = this.$getTop(range.start.row + 1, config); + + stringBuilder.push( + "
" + ); + }; + + // Draws a marker which covers part or whole width of a single screen line + this.drawSingleLineMarker = function(stringBuilder, range, clazz, config, extraLength) { + var height = config.lineHeight; + var width = (range.end.column + (extraLength || 0) - range.start.column) * config.characterWidth; + + var top = this.$getTop(range.start.row, config); + var left = this.$padding + range.start.column * config.characterWidth; + + stringBuilder.push( + "
" + ); + }; + + this.drawFullLineMarker = function(stringBuilder, range, clazz, config) { + var top = this.$getTop(range.start.row, config); + var height = config.lineHeight; + if (range.start.row != range.end.row) + height += this.$getTop(range.end.row, config) - top; + + stringBuilder.push( + "
" + ); + } + +}).call(Marker.prototype); + +exports.Marker = Marker; + +}); diff --git a/lib/ace/layer/text.js b/lib/ace/layer/text.js new file mode 100644 index 0000000000..812dd06618 --- /dev/null +++ b/lib/ace/layer/text.js @@ -0,0 +1,656 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var dom = require("../lib/dom"); +var lang = require("../lib/lang"); +var useragent = require("../lib/useragent"); +var EventEmitter = require("../lib/event_emitter").EventEmitter; + +var Text = function(parentEl) { + this.element = dom.createElement("div"); + this.element.className = "ace_layer ace_text-layer"; + parentEl.appendChild(this.element); + + this.$characterSize = {width: 0, height: 0}; + this.checkForSizeChanges(); + this.$pollSizeChanges(); +}; + +(function() { + + oop.implement(this, EventEmitter); + + this.EOF_CHAR = "\xB6"; //"¶"; + this.EOL_CHAR = "\xAC"; //"¬"; + this.TAB_CHAR = "\u2192"; //"→" "\u21E5"; + this.SPACE_CHAR = "\xB7"; //"·"; + this.$padding = 0; + + this.setPadding = function(padding) { + this.$padding = padding; + this.element.style.padding = "0 " + padding + "px"; + }; + + this.getLineHeight = function() { + return this.$characterSize.height || 1; + }; + + this.getCharacterWidth = function() { + return this.$characterSize.width || 1; + }; + + this.checkForSizeChanges = function() { + var size = this.$measureSizes(); + if (size && (this.$characterSize.width !== size.width || this.$characterSize.height !== size.height)) { + this.$measureNode.style.fontWeight = "bold"; + var boldSize = this.$measureSizes(); + this.$measureNode.style.fontWeight = ""; + this.$characterSize = size; + this.allowBoldFonts = boldSize && boldSize.width === size.width && boldSize.height === size.height; + this._emit("changeCharacterSize", {data: size}); + } + }; + + this.$pollSizeChanges = function() { + var self = this; + this.$pollSizeChangesTimer = setInterval(function() { + self.checkForSizeChanges(); + }, 500); + }; + + this.$fontStyles = { + fontFamily : 1, + fontSize : 1, + fontWeight : 1, + fontStyle : 1, + lineHeight : 1 + }; + + this.$measureSizes = useragent.isIE || useragent.isOldGecko ? function() { + var n = 1000; + if (!this.$measureNode) { + var measureNode = this.$measureNode = dom.createElement("div"); + var style = measureNode.style; + + style.width = style.height = "auto"; + style.left = style.top = (-n * 40) + "px"; + + style.visibility = "hidden"; + style.position = "fixed"; + style.overflow = "visible"; + style.whiteSpace = "nowrap"; + + // in FF 3.6 monospace fonts can have a fixed sub pixel width. + // that's why we have to measure many characters + // Note: characterWidth can be a float! + measureNode.innerHTML = lang.stringRepeat("Xy", n); + + if (this.element.ownerDocument.body) { + this.element.ownerDocument.body.appendChild(measureNode); + } else { + var container = this.element.parentNode; + while (!dom.hasCssClass(container, "ace_editor")) + container = container.parentNode; + container.appendChild(measureNode); + } + } + + // Size and width can be null if the editor is not visible or + // detached from the document + if (!this.element.offsetWidth) + return null; + + var style = this.$measureNode.style; + var computedStyle = dom.computedStyle(this.element); + for (var prop in this.$fontStyles) + style[prop] = computedStyle[prop]; + + var size = { + height: this.$measureNode.offsetHeight, + width: this.$measureNode.offsetWidth / (n * 2) + }; + + // Size and width can be null if the editor is not visible or + // detached from the document + if (size.width == 0 || size.height == 0) + return null; + + return size; + } + : function() { + if (!this.$measureNode) { + var measureNode = this.$measureNode = dom.createElement("div"); + var style = measureNode.style; + + style.width = style.height = "auto"; + style.left = style.top = -100 + "px"; + + style.visibility = "hidden"; + style.position = "fixed"; + style.overflow = "visible"; + style.whiteSpace = "nowrap"; + + measureNode.innerHTML = "X"; + + var container = this.element.parentNode; + while (container && !dom.hasCssClass(container, "ace_editor")) + container = container.parentNode; + + if (!container) + return this.$measureNode = null; + + container.appendChild(measureNode); + } + + var rect = this.$measureNode.getBoundingClientRect(); + + var size = { + height: rect.height, + width: rect.width + }; + + // Size and width can be null if the editor is not visible or + // detached from the document + if (size.width == 0 || size.height == 0) + return null; + + return size; + }; + + this.setSession = function(session) { + this.session = session; + this.$computeTabString(); + }; + + this.showInvisibles = false; + this.setShowInvisibles = function(showInvisibles) { + if (this.showInvisibles == showInvisibles) + return false; + + this.showInvisibles = showInvisibles; + this.$computeTabString(); + return true; + }; + + this.displayIndentGuides = true; + this.setDisplayIndentGuides = function(display) { + if (this.displayIndentGuides == display) + return false; + + this.displayIndentGuides = display; + this.$computeTabString(); + return true; + }; + + this.$tabStrings = []; + this.onChangeTabSize = + this.$computeTabString = function() { + var tabSize = this.session.getTabSize(); + this.tabSize = tabSize; + var tabStr = this.$tabStrings = [0]; + for (var i = 1; i < tabSize + 1; i++) { + if (this.showInvisibles) { + tabStr.push("" + + this.TAB_CHAR + + Array(i).join(" ") + + ""); + } else { + tabStr.push(new Array(i+1).join(" ")); + } + } + if (this.displayIndentGuides) { + this.$indentGuideRe = /\s\S| \t|\t |\s$/; + var className = "ace_indent-guide"; + var content = Array(this.tabSize + 1).join(" "); + var tabContent = content; + if (this.showInvisibles) { + className += " ace_invisible"; + tabContent = this.TAB_CHAR + content.substr(6); + } + + this.$tabStrings[" "] = "" + content + ""; + this.$tabStrings["\t"] = "" + tabContent + ""; + } + }; + + this.updateLines = function(config, firstRow, lastRow) { + // Due to wrap line changes there can be new lines if e.g. + // the line to updated wrapped in the meantime. + if (this.config.lastRow != config.lastRow || + this.config.firstRow != config.firstRow) { + this.scrollLines(config); + } + this.config = config; + + var first = Math.max(firstRow, config.firstRow); + var last = Math.min(lastRow, config.lastRow); + + var lineElements = this.element.childNodes; + var lineElementsIdx = 0; + + for (var row = config.firstRow; row < first; row++) { + var foldLine = this.session.getFoldLine(row); + if (foldLine) { + if (foldLine.containsRow(first)) { + first = foldLine.start.row; + break; + } else { + row = foldLine.end.row; + } + } + lineElementsIdx ++; + } + + var row = first; + var foldLine = this.session.getNextFoldLine(row); + var foldStart = foldLine ? foldLine.start.row : Infinity; + + while (true) { + if (row > foldStart) { + row = foldLine.end.row+1; + foldLine = this.session.getNextFoldLine(row, foldLine); + foldStart = foldLine ? foldLine.start.row :Infinity; + } + if (row > last) + break; + + var lineElement = lineElements[lineElementsIdx++]; + if (lineElement) { + var html = []; + this.$renderLine( + html, row, !this.$useLineGroups(), row == foldStart ? foldLine : false + ); + dom.setInnerHtml(lineElement, html.join("")); + } + row++; + } + }; + + this.scrollLines = function(config) { + var oldConfig = this.config; + this.config = config; + + if (!oldConfig || oldConfig.lastRow < config.firstRow) + return this.update(config); + + if (config.lastRow < oldConfig.firstRow) + return this.update(config); + + var el = this.element; + if (oldConfig.firstRow < config.firstRow) + for (var row=this.session.getFoldedRowCount(oldConfig.firstRow, config.firstRow - 1); row>0; row--) + el.removeChild(el.firstChild); + + if (oldConfig.lastRow > config.lastRow) + for (var row=this.session.getFoldedRowCount(config.lastRow + 1, oldConfig.lastRow); row>0; row--) + el.removeChild(el.lastChild); + + if (config.firstRow < oldConfig.firstRow) { + var fragment = this.$renderLinesFragment(config, config.firstRow, oldConfig.firstRow - 1); + if (el.firstChild) + el.insertBefore(fragment, el.firstChild); + else + el.appendChild(fragment); + } + + if (config.lastRow > oldConfig.lastRow) { + var fragment = this.$renderLinesFragment(config, oldConfig.lastRow + 1, config.lastRow); + el.appendChild(fragment); + } + }; + + this.$renderLinesFragment = function(config, firstRow, lastRow) { + var fragment = this.element.ownerDocument.createDocumentFragment(); + var row = firstRow; + var foldLine = this.session.getNextFoldLine(row); + var foldStart = foldLine ? foldLine.start.row : Infinity; + + while (true) { + if (row > foldStart) { + row = foldLine.end.row+1; + foldLine = this.session.getNextFoldLine(row, foldLine); + foldStart = foldLine ? foldLine.start.row : Infinity; + } + if (row > lastRow) + break; + + var container = dom.createElement("div"); + + var html = []; + // Get the tokens per line as there might be some lines in between + // beeing folded. + this.$renderLine(html, row, false, row == foldStart ? foldLine : false); + + // don't use setInnerHtml since we are working with an empty DIV + container.innerHTML = html.join(""); + if (this.$useLineGroups()) { + container.className = 'ace_line_group'; + fragment.appendChild(container); + } else { + var lines = container.childNodes + while(lines.length) + fragment.appendChild(lines[0]); + } + + row++; + } + return fragment; + }; + + this.update = function(config) { + this.config = config; + + var html = []; + var firstRow = config.firstRow, lastRow = config.lastRow; + + var row = firstRow; + var foldLine = this.session.getNextFoldLine(row); + var foldStart = foldLine ? foldLine.start.row : Infinity; + + while (true) { + if (row > foldStart) { + row = foldLine.end.row+1; + foldLine = this.session.getNextFoldLine(row, foldLine); + foldStart = foldLine ? foldLine.start.row :Infinity; + } + if (row > lastRow) + break; + + if (this.$useLineGroups()) + html.push("
") + + this.$renderLine(html, row, false, row == foldStart ? foldLine : false); + + if (this.$useLineGroups()) + html.push("
"); // end the line group + + row++; + } + this.element = dom.setInnerHtml(this.element, html.join("")); + }; + + this.$textToken = { + "text": true, + "rparen": true, + "lparen": true + }; + + this.$renderToken = function(stringBuilder, screenColumn, token, value) { + var self = this; + var replaceReg = /\t|&|<|( +)|([\x00-\x1f\x80-\xa0\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\u3000\uFEFF])|[\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3000-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]/g; + var replaceFunc = function(c, a, b, tabIdx, idx4) { + if (a) { + return new Array(c.length+1).join(" "); + } else if (c == "&") { + return "&"; + } else if (c == "<") { + return "<"; + } else if (c == "\t") { + var tabSize = self.session.getScreenTabSize(screenColumn + tabIdx); + screenColumn += tabSize - 1; + return self.$tabStrings[tabSize]; + } else if (c == "\u3000") { + // U+3000 is both invisible AND full-width, so must be handled uniquely + var classToUse = self.showInvisibles ? "ace_cjk ace_invisible" : "ace_cjk"; + var space = self.showInvisibles ? self.SPACE_CHAR : ""; + screenColumn += 1; + return "" + space + ""; + } else if (b) { + return "" + self.SPACE_CHAR + ""; + } else { + screenColumn += 1; + return "" + c + ""; + } + }; + + var output = value.replace(replaceReg, replaceFunc); + + if (!this.$textToken[token.type]) { + var classes = "ace_" + token.type.replace(/\./g, " ace_"); + var style = ""; + if (token.type == "fold") + style = " style='width:" + (token.value.length * this.config.characterWidth) + "px;' "; + stringBuilder.push("", output, ""); + } + else { + stringBuilder.push(output); + } + return screenColumn + value.length; + }; + + this.renderIndentGuide = function(stringBuilder, value) { + var cols = value.search(this.$indentGuideRe); + if (cols <= 0) + return value; + if (value[0] == " ") { + cols -= cols % this.tabSize; + stringBuilder.push(Array(cols/this.tabSize + 1).join(this.$tabStrings[" "])); + return value.substr(cols); + } else if (value[0] == "\t") { + stringBuilder.push(Array(cols + 1).join(this.$tabStrings["\t"])); + return value.substr(cols); + } + return value; + }; + + this.$renderWrappedLine = function(stringBuilder, tokens, splits, onlyContents) { + var chars = 0; + var split = 0; + var splitChars = splits[0]; + var screenColumn = 0; + + for (var i = 0; i < tokens.length; i++) { + var token = tokens[i]; + var value = token.value; + if (i == 0 && this.displayIndentGuides) { + chars = value.length; + value = this.renderIndentGuide(stringBuilder, value); + if (!value) + continue; + chars -= value.length; + } + + if (chars + value.length < splitChars) { + screenColumn = this.$renderToken(stringBuilder, screenColumn, token, value); + chars += value.length; + } else { + while (chars + value.length >= splitChars) { + screenColumn = this.$renderToken( + stringBuilder, screenColumn, + token, value.substring(0, splitChars - chars) + ); + value = value.substring(splitChars - chars); + chars = splitChars; + + if (!onlyContents) { + stringBuilder.push("
", + "
" + ); + } + + split ++; + screenColumn = 0; + splitChars = splits[split] || Number.MAX_VALUE; + } + if (value.length != 0) { + chars += value.length; + screenColumn = this.$renderToken( + stringBuilder, screenColumn, token, value + ); + } + } + } + }; + + this.$renderSimpleLine = function(stringBuilder, tokens) { + var screenColumn = 0; + var token = tokens[0]; + var value = token.value; + if (this.displayIndentGuides) + value = this.renderIndentGuide(stringBuilder, value); + if (value) + screenColumn = this.$renderToken(stringBuilder, screenColumn, token, value); + for (var i = 1; i < tokens.length; i++) { + token = tokens[i]; + value = token.value; + screenColumn = this.$renderToken(stringBuilder, screenColumn, token, value); + } + }; + + // row is either first row of foldline or not in fold + this.$renderLine = function(stringBuilder, row, onlyContents, foldLine) { + if (!foldLine && foldLine != false) + foldLine = this.session.getFoldLine(row); + + if (foldLine) + var tokens = this.$getFoldLineTokens(row, foldLine); + else + var tokens = this.session.getTokens(row); + + + if (!onlyContents) { + stringBuilder.push( + "
" + ); + } + + if (tokens.length) { + var splits = this.session.getRowSplitData(row); + if (splits && splits.length) + this.$renderWrappedLine(stringBuilder, tokens, splits, onlyContents); + else + this.$renderSimpleLine(stringBuilder, tokens); + } + + if (this.showInvisibles) { + if (foldLine) + row = foldLine.end.row + + stringBuilder.push( + "", + row == this.session.getLength() - 1 ? this.EOF_CHAR : this.EOL_CHAR, + "" + ); + } + if (!onlyContents) + stringBuilder.push("
"); + }; + + this.$getFoldLineTokens = function(row, foldLine) { + var session = this.session; + var renderTokens = []; + + function addTokens(tokens, from, to) { + var idx = 0, col = 0; + while ((col + tokens[idx].value.length) < from) { + col += tokens[idx].value.length; + idx++; + + if (idx == tokens.length) + return; + } + if (col != from) { + var value = tokens[idx].value.substring(from - col); + // Check if the token value is longer then the from...to spacing. + if (value.length > (to - from)) + value = value.substring(0, to - from); + + renderTokens.push({ + type: tokens[idx].type, + value: value + }); + + col = from + value.length; + idx += 1; + } + + while (col < to && idx < tokens.length) { + var value = tokens[idx].value; + if (value.length + col > to) { + renderTokens.push({ + type: tokens[idx].type, + value: value.substring(0, to - col) + }); + } else + renderTokens.push(tokens[idx]); + col += value.length; + idx += 1; + } + } + + var tokens = session.getTokens(row); + foldLine.walk(function(placeholder, row, column, lastColumn, isNewRow) { + if (placeholder != null) { + renderTokens.push({ + type: "fold", + value: placeholder + }); + } else { + if (isNewRow) + tokens = session.getTokens(row); + + if (tokens.length) + addTokens(tokens, lastColumn, column); + } + }, foldLine.end.row, this.session.getLine(foldLine.end.row).length); + + return renderTokens; + }; + + this.$useLineGroups = function() { + // For the updateLines function to work correctly, it's important that the + // child nodes of this.element correspond on a 1-to-1 basis to rows in the + // document (as distinct from lines on the screen). For sessions that are + // wrapped, this means we need to add a layer to the node hierarchy (tagged + // with the class name ace_line_group). + return this.session.getUseWrapMode(); + }; + + this.destroy = function() { + clearInterval(this.$pollSizeChangesTimer); + if (this.$measureNode) + this.$measureNode.parentNode.removeChild(this.$measureNode); + delete this.$measureNode; + }; + +}).call(Text.prototype); + +exports.Text = Text; + +}); diff --git a/lib/ace/layer/text_test.js b/lib/ace/layer/text_test.js new file mode 100644 index 0000000000..b0aad573ca --- /dev/null +++ b/lib/ace/layer/text_test.js @@ -0,0 +1,125 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); + require("../test/mockdom"); +} + +define(function(require, exports, module) { +"use strict"; + +var assert = require("../test/assertions"); +var EditSession = require("../edit_session").EditSession; +var TextLayer = require("./text").Text; +var JavaScriptMode = require("../mode/javascript").Mode; + +module.exports = { + + setUp: function(next) { + this.session = new EditSession(""); + this.session.setMode(new JavaScriptMode()); + this.textLayer = new TextLayer(document.createElement("div")); + this.textLayer.setSession(this.session); + this.textLayer.config = { + characterWidth: 10, + lineHeight: 20 + }; + next() + }, + + "test: render line with hard tabs should render the same as lines with soft tabs" : function() { + this.session.setValue("a\ta\ta\t\na a a \n"); + this.textLayer.$computeTabString(); + + // row with hard tabs + var stringBuilder = []; + this.textLayer.$renderLine(stringBuilder, 0); + + // row with soft tabs + var stringBuilder2 = []; + this.textLayer.$renderLine(stringBuilder2, 1); + assert.equal(stringBuilder.join(""), stringBuilder2.join("")); + }, + + "test rendering width of ideographic space (U+3000)" : function() { + this.session.setValue("\u3000"); + + var stringBuilder = []; + this.textLayer.$renderLine(stringBuilder, 0, true); + assert.equal(stringBuilder.join(""), ""); + + this.textLayer.setShowInvisibles(true); + var stringBuilder = []; + this.textLayer.$renderLine(stringBuilder, 0, true); + assert.equal( + stringBuilder.join(""), + "" + this.textLayer.SPACE_CHAR + "" + + "\xB6" + ); + }, + + "test rendering of indent guides" : function() { + var textLayer = this.textLayer + var EOL = "" + textLayer.EOL_CHAR + ""; + var SPACE = function(i) {return Array(i+1).join(" ")} + var TAB = function(i) {return textLayer.TAB_CHAR + SPACE(i-1)} + function testRender(results) { + for (var i = results.length; i--; ) { + var stringBuilder = []; + textLayer.$renderLine(stringBuilder, i, true); + assert.equal(stringBuilder.join(""), results[i]); + } + } + + this.session.setValue(" \n\t\tf\n "); + testRender([ + "" + SPACE(4) + "" + SPACE(2), + "" + SPACE(4) + "" + SPACE(4) + "f", + SPACE(3) + ]); + this.textLayer.setShowInvisibles(true); + testRender([ + "" + SPACE(4) + "" + SPACE(2) + EOL, + "" + TAB(4) + "" + TAB(4) + "f" + EOL, + ]); + this.textLayer.setDisplayIndentGuides(false); + testRender([ + SPACE(6) + EOL, + "" + TAB(4) + "" + TAB(4) + "f" + EOL + ]); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec() +} diff --git a/lib/ace/lib/browser_focus.js b/lib/ace/lib/browser_focus.js new file mode 100644 index 0000000000..375970154a --- /dev/null +++ b/lib/ace/lib/browser_focus.js @@ -0,0 +1,95 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("./oop"); +var event = require("./event"); +var EventEmitter = require("./event_emitter").EventEmitter; + +/* + * This class keeps track of the focus state of the given window. + * Focus changes for example when the user switches a browser tab, + * goes to the location bar or switches to another application. + */ +var BrowserFocus = function(win) { + win = win || window; + + this.lastFocus = new Date().getTime(); + this._isFocused = true; + + var _self = this; + + // IE < 9 supports focusin and focusout events + if ("onfocusin" in win.document) { + event.addListener(win.document, "focusin", function(e) { + _self._setFocused(true); + }); + + event.addListener(win.document, "focusout", function(e) { + _self._setFocused(!!e.toElement); + }); + } + else { + event.addListener(win, "blur", function(e) { + _self._setFocused(false); + }); + + event.addListener(win, "focus", function(e) { + _self._setFocused(true); + }); + } +}; + +(function(){ + + oop.implement(this, EventEmitter); + + this.isFocused = function() { + return this._isFocused; + }; + + this._setFocused = function(isFocused) { + if (this._isFocused == isFocused) + return; + + if (isFocused) + this.lastFocus = new Date().getTime(); + + this._isFocused = isFocused; + this._emit("changeFocus"); + }; + +}).call(BrowserFocus.prototype); + + +exports.BrowserFocus = BrowserFocus; +}); diff --git a/lib/ace/lib/dom.js b/lib/ace/lib/dom.js new file mode 100644 index 0000000000..04f8bf5f44 --- /dev/null +++ b/lib/ace/lib/dom.js @@ -0,0 +1,282 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var XHTML_NS = "http://www.w3.org/1999/xhtml"; + +exports.createElement = function(tag, ns) { + return document.createElementNS ? + document.createElementNS(ns || XHTML_NS, tag) : + document.createElement(tag); +}; + +exports.setText = function(elem, text) { + if (elem.innerText !== undefined) { + elem.innerText = text; + } + if (elem.textContent !== undefined) { + elem.textContent = text; + } +}; + +exports.hasCssClass = function(el, name) { + var classes = el.className.split(/\s+/g); + return classes.indexOf(name) !== -1; +}; + +/* +* Add a CSS class to the list of classes on the given node +*/ +exports.addCssClass = function(el, name) { + if (!exports.hasCssClass(el, name)) { + el.className += " " + name; + } +}; + +/* +* Remove a CSS class from the list of classes on the given node +*/ +exports.removeCssClass = function(el, name) { + var classes = el.className.split(/\s+/g); + while (true) { + var index = classes.indexOf(name); + if (index == -1) { + break; + } + classes.splice(index, 1); + } + el.className = classes.join(" "); +}; + +exports.toggleCssClass = function(el, name) { + var classes = el.className.split(/\s+/g), add = true; + while (true) { + var index = classes.indexOf(name); + if (index == -1) { + break; + } + add = false; + classes.splice(index, 1); + } + if(add) + classes.push(name); + + el.className = classes.join(" "); + return add; +}; + +/* + * Add or remove a CSS class from the list of classes on the given node + * depending on the value of include + */ +exports.setCssClass = function(node, className, include) { + if (include) { + exports.addCssClass(node, className); + } else { + exports.removeCssClass(node, className); + } +}; + +exports.hasCssString = function(id, doc) { + var index = 0, sheets; + doc = doc || document; + + if (doc.createStyleSheet && (sheets = doc.styleSheets)) { + while (index < sheets.length) + if (sheets[index++].owningElement.id === id) return true; + } else if ((sheets = doc.getElementsByTagName("style"))) { + while (index < sheets.length) + if (sheets[index++].id === id) return true; + } + + return false; +}; + +exports.importCssString = function importCssString(cssText, id, doc) { + doc = doc || document; + // If style is already imported return immediately. + if (id && exports.hasCssString(id, doc)) + return null; + + var style; + + if (doc.createStyleSheet) { + style = doc.createStyleSheet(); + style.cssText = cssText; + if (id) + style.owningElement.id = id; + } else { + style = doc.createElementNS + ? doc.createElementNS(XHTML_NS, "style") + : doc.createElement("style"); + + style.appendChild(doc.createTextNode(cssText)); + if (id) + style.id = id; + + var head = doc.getElementsByTagName("head")[0] || doc.documentElement; + head.appendChild(style); + } +}; + +exports.importCssStylsheet = function(uri, doc) { + if (doc.createStyleSheet) { + doc.createStyleSheet(uri); + } else { + var link = exports.createElement('link'); + link.rel = 'stylesheet'; + link.href = uri; + + var head = doc.getElementsByTagName("head")[0] || doc.documentElement; + head.appendChild(link); + } +}; + +exports.getInnerWidth = function(element) { + return ( + parseInt(exports.computedStyle(element, "paddingLeft"), 10) + + parseInt(exports.computedStyle(element, "paddingRight"), 10) + + element.clientWidth + ); +}; + +exports.getInnerHeight = function(element) { + return ( + parseInt(exports.computedStyle(element, "paddingTop"), 10) + + parseInt(exports.computedStyle(element, "paddingBottom"), 10) + + element.clientHeight + ); +}; + +if (window.pageYOffset !== undefined) { + exports.getPageScrollTop = function() { + return window.pageYOffset; + }; + + exports.getPageScrollLeft = function() { + return window.pageXOffset; + }; +} +else { + exports.getPageScrollTop = function() { + return document.body.scrollTop; + }; + + exports.getPageScrollLeft = function() { + return document.body.scrollLeft; + }; +} + +if (window.getComputedStyle) + exports.computedStyle = function(element, style) { + if (style) + return (window.getComputedStyle(element, "") || {})[style] || ""; + return window.getComputedStyle(element, "") || {}; + }; +else + exports.computedStyle = function(element, style) { + if (style) + return element.currentStyle[style]; + return element.currentStyle; + }; + +exports.scrollbarWidth = function(document) { + + var inner = exports.createElement("p"); + inner.style.width = "100%"; + inner.style.minWidth = "0px"; + inner.style.height = "200px"; + + var outer = exports.createElement("div"); + var style = outer.style; + + style.position = "absolute"; + style.left = "-10000px"; + style.overflow = "hidden"; + style.width = "200px"; + style.minWidth = "0px"; + style.height = "150px"; + + outer.appendChild(inner); + + var body = document.body || document.documentElement; + body.appendChild(outer); + + var noScrollbar = inner.offsetWidth; + + style.overflow = "scroll"; + var withScrollbar = inner.offsetWidth; + + if (noScrollbar == withScrollbar) { + withScrollbar = outer.clientWidth; + } + + body.removeChild(outer); + + return noScrollbar-withScrollbar; +}; + +/* + * Optimized set innerHTML. This is faster than plain innerHTML if the element + * already contains a lot of child elements. + * + * See http://blog.stevenlevithan.com/archives/faster-than-innerhtml for details + */ +exports.setInnerHtml = function(el, innerHtml) { + var element = el.cloneNode(false);//document.createElement("div"); + element.innerHTML = innerHtml; + el.parentNode.replaceChild(element, el); + return element; +}; + +exports.setInnerText = function(el, innerText) { + var document = el.ownerDocument; + if (document.body && "textContent" in document.body) + el.textContent = innerText; + else + el.innerText = innerText; + +}; + +exports.getInnerText = function(el) { + var document = el.ownerDocument; + if (document.body && "textContent" in document.body) + return el.textContent; + else + return el.innerText || el.textContent || ""; +}; + +exports.getParentWindow = function(document) { + return document.defaultView || document.parentWindow; +}; + +}); diff --git a/lib/ace/lib/es5-shim.js b/lib/ace/lib/es5-shim.js new file mode 100644 index 0000000000..3a3b68c56c --- /dev/null +++ b/lib/ace/lib/es5-shim.js @@ -0,0 +1,1082 @@ +// vim: ts=4 sts=4 sw=4 expandtab +// -- kriskowal Kris Kowal Copyright (C) 2009-2011 MIT License +// -- tlrobinson Tom Robinson Copyright (C) 2009-2010 MIT License (Narwhal Project) +// -- dantman Daniel Friesen Copyright (C) 2010 XXX TODO License or CLA +// -- fschaefer Florian Schäfer Copyright (C) 2010 MIT License +// -- Gozala Irakli Gozalishvili Copyright (C) 2010 MIT License +// -- kitcambridge Kit Cambridge Copyright (C) 2011 MIT License +// -- kossnocorp Sasha Koss XXX TODO License or CLA +// -- bryanforbes Bryan Forbes XXX TODO License or CLA +// -- killdream Quildreen Motta Copyright (C) 2011 MIT Licence +// -- michaelficarra Michael Ficarra Copyright (C) 2011 3-clause BSD License +// -- sharkbrainguy Gerard Paapu Copyright (C) 2011 MIT License +// -- bbqsrc Brendan Molloy (C) 2011 Creative Commons Zero (public domain) +// -- iwyg XXX TODO License or CLA +// -- DomenicDenicola Domenic Denicola Copyright (C) 2011 MIT License +// -- xavierm02 Montillet Xavier XXX TODO License or CLA +// -- Raynos Raynos XXX TODO License or CLA +// -- samsonjs Sami Samhuri Copyright (C) 2010 MIT License +// -- rwldrn Rick Waldron Copyright (C) 2011 MIT License +// -- lexer Alexey Zakharov XXX TODO License or CLA + +/*! + Copyright (c) 2009, 280 North Inc. http://280north.com/ + MIT License. http://github.com/280north/narwhal/blob/master/README.md +*/ + +define(function(require, exports, module) { + +/* + * Brings an environment as close to ECMAScript 5 compliance + * as is possible with the facilities of erstwhile engines. + * + * Annotated ES5: http://es5.github.com/ (specific links below) + * ES5 Spec: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf + * + * @module + */ + +/*whatsupdoc*/ + +// +// Function +// ======== +// + +// ES-5 15.3.4.5 +// http://es5.github.com/#x15.3.4.5 + +if (!Function.prototype.bind) { + Function.prototype.bind = function bind(that) { // .length is 1 + // 1. Let Target be the this value. + var target = this; + // 2. If IsCallable(Target) is false, throw a TypeError exception. + if (typeof target != "function") + throw new TypeError(); // TODO message + // 3. Let A be a new (possibly empty) internal list of all of the + // argument values provided after thisArg (arg1, arg2 etc), in order. + // XXX slicedArgs will stand in for "A" if used + var args = slice.call(arguments, 1); // for normal call + // 4. Let F be a new native ECMAScript object. + // 11. Set the [[Prototype]] internal property of F to the standard + // built-in Function prototype object as specified in 15.3.3.1. + // 12. Set the [[Call]] internal property of F as described in + // 15.3.4.5.1. + // 13. Set the [[Construct]] internal property of F as described in + // 15.3.4.5.2. + // 14. Set the [[HasInstance]] internal property of F as described in + // 15.3.4.5.3. + var bound = function () { + + if (this instanceof bound) { + // 15.3.4.5.2 [[Construct]] + // When the [[Construct]] internal method of a function object, + // F that was created using the bind function is called with a + // list of arguments ExtraArgs, the following steps are taken: + // 1. Let target be the value of F's [[TargetFunction]] + // internal property. + // 2. If target has no [[Construct]] internal method, a + // TypeError exception is thrown. + // 3. Let boundArgs be the value of F's [[BoundArgs]] internal + // property. + // 4. Let args be a new list containing the same values as the + // list boundArgs in the same order followed by the same + // values as the list ExtraArgs in the same order. + // 5. Return the result of calling the [[Construct]] internal + // method of target providing args as the arguments. + + var F = function(){}; + F.prototype = target.prototype; + var self = new F; + + var result = target.apply( + self, + args.concat(slice.call(arguments)) + ); + if (result !== null && Object(result) === result) + return result; + return self; + + } else { + // 15.3.4.5.1 [[Call]] + // When the [[Call]] internal method of a function object, F, + // which was created using the bind function is called with a + // this value and a list of arguments ExtraArgs, the following + // steps are taken: + // 1. Let boundArgs be the value of F's [[BoundArgs]] internal + // property. + // 2. Let boundThis be the value of F's [[BoundThis]] internal + // property. + // 3. Let target be the value of F's [[TargetFunction]] internal + // property. + // 4. Let args be a new list containing the same values as the + // list boundArgs in the same order followed by the same + // values as the list ExtraArgs in the same order. + // 5. Return the result of calling the [[Call]] internal method + // of target providing boundThis as the this value and + // providing args as the arguments. + + // equiv: target.call(this, ...boundArgs, ...args) + return target.apply( + that, + args.concat(slice.call(arguments)) + ); + + } + + }; + // XXX bound.length is never writable, so don't even try + // + // 15. If the [[Class]] internal property of Target is "Function", then + // a. Let L be the length property of Target minus the length of A. + // b. Set the length own property of F to either 0 or L, whichever is + // larger. + // 16. Else set the length own property of F to 0. + // 17. Set the attributes of the length own property of F to the values + // specified in 15.3.5.1. + + // TODO + // 18. Set the [[Extensible]] internal property of F to true. + + // TODO + // 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3). + // 20. Call the [[DefineOwnProperty]] internal method of F with + // arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]: + // thrower, [[Enumerable]]: false, [[Configurable]]: false}, and + // false. + // 21. Call the [[DefineOwnProperty]] internal method of F with + // arguments "arguments", PropertyDescriptor {[[Get]]: thrower, + // [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, + // and false. + + // TODO + // NOTE Function objects created using Function.prototype.bind do not + // have a prototype property or the [[Code]], [[FormalParameters]], and + // [[Scope]] internal properties. + // XXX can't delete prototype in pure-js. + + // 22. Return F. + return bound; + }; +} + +// Shortcut to an often accessed properties, in order to avoid multiple +// dereference that costs universally. +// _Please note: Shortcuts are defined after `Function.prototype.bind` as we +// us it in defining shortcuts. +var call = Function.prototype.call; +var prototypeOfArray = Array.prototype; +var prototypeOfObject = Object.prototype; +var slice = prototypeOfArray.slice; +var toString = call.bind(prototypeOfObject.toString); +var owns = call.bind(prototypeOfObject.hasOwnProperty); + +// If JS engine supports accessors creating shortcuts. +var defineGetter; +var defineSetter; +var lookupGetter; +var lookupSetter; +var supportsAccessors; +if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) { + defineGetter = call.bind(prototypeOfObject.__defineGetter__); + defineSetter = call.bind(prototypeOfObject.__defineSetter__); + lookupGetter = call.bind(prototypeOfObject.__lookupGetter__); + lookupSetter = call.bind(prototypeOfObject.__lookupSetter__); +} + +// +// Array +// ===== +// + +// ES5 15.4.3.2 +// http://es5.github.com/#x15.4.3.2 +// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray +if (!Array.isArray) { + Array.isArray = function isArray(obj) { + return toString(obj) == "[object Array]"; + }; +} + +// The IsCallable() check in the Array functions +// has been replaced with a strict check on the +// internal class of the object to trap cases where +// the provided function was actually a regular +// expression literal, which in V8 and +// JavaScriptCore is a typeof "function". Only in +// V8 are regular expression literals permitted as +// reduce parameters, so it is desirable in the +// general case for the shim to match the more +// strict and common behavior of rejecting regular +// expressions. + +// ES5 15.4.4.18 +// http://es5.github.com/#x15.4.4.18 +// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/forEach +if (!Array.prototype.forEach) { + Array.prototype.forEach = function forEach(fun /*, thisp*/) { + var self = toObject(this), + thisp = arguments[1], + i = 0, + length = self.length >>> 0; + + // If no callback function or if callback is not a callable function + if (toString(fun) != "[object Function]") { + throw new TypeError(); // TODO message + } + + while (i < length) { + if (i in self) { + // Invoke the callback function with call, passing arguments: + // context, property value, property key, thisArg object context + fun.call(thisp, self[i], i, self); + } + i++; + } + }; +} + +// ES5 15.4.4.19 +// http://es5.github.com/#x15.4.4.19 +// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map +if (!Array.prototype.map) { + Array.prototype.map = function map(fun /*, thisp*/) { + var self = toObject(this), + length = self.length >>> 0, + result = Array(length), + thisp = arguments[1]; + + // If no callback function or if callback is not a callable function + if (toString(fun) != "[object Function]") { + throw new TypeError(); // TODO message + } + + for (var i = 0; i < length; i++) { + if (i in self) + result[i] = fun.call(thisp, self[i], i, self); + } + return result; + }; +} + +// ES5 15.4.4.20 +// http://es5.github.com/#x15.4.4.20 +// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter +if (!Array.prototype.filter) { + Array.prototype.filter = function filter(fun /*, thisp */) { + var self = toObject(this), + length = self.length >>> 0, + result = [], + thisp = arguments[1]; + + // If no callback function or if callback is not a callable function + if (toString(fun) != "[object Function]") { + throw new TypeError(); // TODO message + } + + for (var i = 0; i < length; i++) { + if (i in self && fun.call(thisp, self[i], i, self)) + result.push(self[i]); + } + return result; + }; +} + +// ES5 15.4.4.16 +// http://es5.github.com/#x15.4.4.16 +// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every +if (!Array.prototype.every) { + Array.prototype.every = function every(fun /*, thisp */) { + var self = toObject(this), + length = self.length >>> 0, + thisp = arguments[1]; + + // If no callback function or if callback is not a callable function + if (toString(fun) != "[object Function]") { + throw new TypeError(); // TODO message + } + + for (var i = 0; i < length; i++) { + if (i in self && !fun.call(thisp, self[i], i, self)) + return false; + } + return true; + }; +} + +// ES5 15.4.4.17 +// http://es5.github.com/#x15.4.4.17 +// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some +if (!Array.prototype.some) { + Array.prototype.some = function some(fun /*, thisp */) { + var self = toObject(this), + length = self.length >>> 0, + thisp = arguments[1]; + + // If no callback function or if callback is not a callable function + if (toString(fun) != "[object Function]") { + throw new TypeError(); // TODO message + } + + for (var i = 0; i < length; i++) { + if (i in self && fun.call(thisp, self[i], i, self)) + return true; + } + return false; + }; +} + +// ES5 15.4.4.21 +// http://es5.github.com/#x15.4.4.21 +// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce +if (!Array.prototype.reduce) { + Array.prototype.reduce = function reduce(fun /*, initial*/) { + var self = toObject(this), + length = self.length >>> 0; + + // If no callback function or if callback is not a callable function + if (toString(fun) != "[object Function]") { + throw new TypeError(); // TODO message + } + + // no value to return if no initial value and an empty array + if (!length && arguments.length == 1) + throw new TypeError(); // TODO message + + var i = 0; + var result; + if (arguments.length >= 2) { + result = arguments[1]; + } else { + do { + if (i in self) { + result = self[i++]; + break; + } + + // if array contains no values, no initial value to return + if (++i >= length) + throw new TypeError(); // TODO message + } while (true); + } + + for (; i < length; i++) { + if (i in self) + result = fun.call(void 0, result, self[i], i, self); + } + + return result; + }; +} + +// ES5 15.4.4.22 +// http://es5.github.com/#x15.4.4.22 +// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight +if (!Array.prototype.reduceRight) { + Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) { + var self = toObject(this), + length = self.length >>> 0; + + // If no callback function or if callback is not a callable function + if (toString(fun) != "[object Function]") { + throw new TypeError(); // TODO message + } + + // no value to return if no initial value, empty array + if (!length && arguments.length == 1) + throw new TypeError(); // TODO message + + var result, i = length - 1; + if (arguments.length >= 2) { + result = arguments[1]; + } else { + do { + if (i in self) { + result = self[i--]; + break; + } + + // if array contains no values, no initial value to return + if (--i < 0) + throw new TypeError(); // TODO message + } while (true); + } + + do { + if (i in this) + result = fun.call(void 0, result, self[i], i, self); + } while (i--); + + return result; + }; +} + +// ES5 15.4.4.14 +// http://es5.github.com/#x15.4.4.14 +// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf +if (!Array.prototype.indexOf) { + Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) { + var self = toObject(this), + length = self.length >>> 0; + + if (!length) + return -1; + + var i = 0; + if (arguments.length > 1) + i = toInteger(arguments[1]); + + // handle negative indices + i = i >= 0 ? i : Math.max(0, length + i); + for (; i < length; i++) { + if (i in self && self[i] === sought) { + return i; + } + } + return -1; + }; +} + +// ES5 15.4.4.15 +// http://es5.github.com/#x15.4.4.15 +// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf +if (!Array.prototype.lastIndexOf) { + Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) { + var self = toObject(this), + length = self.length >>> 0; + + if (!length) + return -1; + var i = length - 1; + if (arguments.length > 1) + i = Math.min(i, toInteger(arguments[1])); + // handle negative indices + i = i >= 0 ? i : length - Math.abs(i); + for (; i >= 0; i--) { + if (i in self && sought === self[i]) + return i; + } + return -1; + }; +} + +// +// Object +// ====== +// + +// ES5 15.2.3.2 +// http://es5.github.com/#x15.2.3.2 +if (!Object.getPrototypeOf) { + // https://github.com/kriskowal/es5-shim/issues#issue/2 + // http://ejohn.org/blog/objectgetprototypeof/ + // recommended by fschaefer on github + Object.getPrototypeOf = function getPrototypeOf(object) { + return object.__proto__ || ( + object.constructor ? + object.constructor.prototype : + prototypeOfObject + ); + }; +} + +// ES5 15.2.3.3 +// http://es5.github.com/#x15.2.3.3 +if (!Object.getOwnPropertyDescriptor) { + var ERR_NON_OBJECT = "Object.getOwnPropertyDescriptor called on a " + + "non-object: "; + Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) { + if ((typeof object != "object" && typeof object != "function") || object === null) + throw new TypeError(ERR_NON_OBJECT + object); + // If object does not owns property return undefined immediately. + if (!owns(object, property)) + return; + + var descriptor, getter, setter; + + // If object has a property then it's for sure both `enumerable` and + // `configurable`. + descriptor = { enumerable: true, configurable: true }; + + // If JS engine supports accessor properties then property may be a + // getter or setter. + if (supportsAccessors) { + // Unfortunately `__lookupGetter__` will return a getter even + // if object has own non getter property along with a same named + // inherited getter. To avoid misbehavior we temporary remove + // `__proto__` so that `__lookupGetter__` will return getter only + // if it's owned by an object. + var prototype = object.__proto__; + object.__proto__ = prototypeOfObject; + + var getter = lookupGetter(object, property); + var setter = lookupSetter(object, property); + + // Once we have getter and setter we can put values back. + object.__proto__ = prototype; + + if (getter || setter) { + if (getter) descriptor.get = getter; + if (setter) descriptor.set = setter; + + // If it was accessor property we're done and return here + // in order to avoid adding `value` to the descriptor. + return descriptor; + } + } + + // If we got this far we know that object has an own property that is + // not an accessor so we set it as a value and return descriptor. + descriptor.value = object[property]; + return descriptor; + }; +} + +// ES5 15.2.3.4 +// http://es5.github.com/#x15.2.3.4 +if (!Object.getOwnPropertyNames) { + Object.getOwnPropertyNames = function getOwnPropertyNames(object) { + return Object.keys(object); + }; +} + +// ES5 15.2.3.5 +// http://es5.github.com/#x15.2.3.5 +if (!Object.create) { + var createEmpty; + if (Object.prototype.__proto__ === null) { + createEmpty = function () { + return { "__proto__": null }; + }; + } else { + // In old IE __proto__ can't be used to manually set `null` + createEmpty = function () { + var empty = {}; + for (var i in empty) + empty[i] = null; + empty.constructor = + empty.hasOwnProperty = + empty.propertyIsEnumerable = + empty.isPrototypeOf = + empty.toLocaleString = + empty.toString = + empty.valueOf = + empty.__proto__ = null; + return empty; + } + } + + Object.create = function create(prototype, properties) { + var object; + if (prototype === null) { + object = createEmpty(); + } else { + if (typeof prototype != "object") + throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'"); + var Type = function () {}; + Type.prototype = prototype; + object = new Type(); + // IE has no built-in implementation of `Object.getPrototypeOf` + // neither `__proto__`, but this manually setting `__proto__` will + // guarantee that `Object.getPrototypeOf` will work as expected with + // objects created using `Object.create` + object.__proto__ = prototype; + } + if (properties !== void 0) + Object.defineProperties(object, properties); + return object; + }; +} + +// ES5 15.2.3.6 +// http://es5.github.com/#x15.2.3.6 + +// Patch for WebKit and IE8 standard mode +// Designed by hax +// related issue: https://github.com/kriskowal/es5-shim/issues#issue/5 +// IE8 Reference: +// http://msdn.microsoft.com/en-us/library/dd282900.aspx +// http://msdn.microsoft.com/en-us/library/dd229916.aspx +// WebKit Bugs: +// https://bugs.webkit.org/show_bug.cgi?id=36423 + +function doesDefinePropertyWork(object) { + try { + Object.defineProperty(object, "sentinel", {}); + return "sentinel" in object; + } catch (exception) { + // returns falsy + } +} + +// check whether defineProperty works if it's given. Otherwise, +// shim partially. +if (Object.defineProperty) { + var definePropertyWorksOnObject = doesDefinePropertyWork({}); + var definePropertyWorksOnDom = typeof document == "undefined" || + doesDefinePropertyWork(document.createElement("div")); + if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) { + var definePropertyFallback = Object.defineProperty; + } +} + +if (!Object.defineProperty || definePropertyFallback) { + var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: "; + var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: " + var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " + + "on this javascript engine"; + + Object.defineProperty = function defineProperty(object, property, descriptor) { + if ((typeof object != "object" && typeof object != "function") || object === null) + throw new TypeError(ERR_NON_OBJECT_TARGET + object); + if ((typeof descriptor != "object" && typeof descriptor != "function") || descriptor === null) + throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor); + + // make a valiant attempt to use the real defineProperty + // for I8's DOM elements. + if (definePropertyFallback) { + try { + return definePropertyFallback.call(Object, object, property, descriptor); + } catch (exception) { + // try the shim if the real one doesn't work + } + } + + // If it's a data property. + if (owns(descriptor, "value")) { + // fail silently if "writable", "enumerable", or "configurable" + // are requested but not supported + /* + // alternate approach: + if ( // can't implement these features; allow false but not true + !(owns(descriptor, "writable") ? descriptor.writable : true) || + !(owns(descriptor, "enumerable") ? descriptor.enumerable : true) || + !(owns(descriptor, "configurable") ? descriptor.configurable : true) + ) + throw new RangeError( + "This implementation of Object.defineProperty does not " + + "support configurable, enumerable, or writable." + ); + */ + + if (supportsAccessors && (lookupGetter(object, property) || + lookupSetter(object, property))) + { + // As accessors are supported only on engines implementing + // `__proto__` we can safely override `__proto__` while defining + // a property to make sure that we don't hit an inherited + // accessor. + var prototype = object.__proto__; + object.__proto__ = prototypeOfObject; + // Deleting a property anyway since getter / setter may be + // defined on object itself. + delete object[property]; + object[property] = descriptor.value; + // Setting original `__proto__` back now. + object.__proto__ = prototype; + } else { + object[property] = descriptor.value; + } + } else { + if (!supportsAccessors) + throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED); + // If we got that far then getters and setters can be defined !! + if (owns(descriptor, "get")) + defineGetter(object, property, descriptor.get); + if (owns(descriptor, "set")) + defineSetter(object, property, descriptor.set); + } + + return object; + }; +} + +// ES5 15.2.3.7 +// http://es5.github.com/#x15.2.3.7 +if (!Object.defineProperties) { + Object.defineProperties = function defineProperties(object, properties) { + for (var property in properties) { + if (owns(properties, property)) + Object.defineProperty(object, property, properties[property]); + } + return object; + }; +} + +// ES5 15.2.3.8 +// http://es5.github.com/#x15.2.3.8 +if (!Object.seal) { + Object.seal = function seal(object) { + // this is misleading and breaks feature-detection, but + // allows "securable" code to "gracefully" degrade to working + // but insecure code. + return object; + }; +} + +// ES5 15.2.3.9 +// http://es5.github.com/#x15.2.3.9 +if (!Object.freeze) { + Object.freeze = function freeze(object) { + // this is misleading and breaks feature-detection, but + // allows "securable" code to "gracefully" degrade to working + // but insecure code. + return object; + }; +} + +// detect a Rhino bug and patch it +try { + Object.freeze(function () {}); +} catch (exception) { + Object.freeze = (function freeze(freezeObject) { + return function freeze(object) { + if (typeof object == "function") { + return object; + } else { + return freezeObject(object); + } + }; + })(Object.freeze); +} + +// ES5 15.2.3.10 +// http://es5.github.com/#x15.2.3.10 +if (!Object.preventExtensions) { + Object.preventExtensions = function preventExtensions(object) { + // this is misleading and breaks feature-detection, but + // allows "securable" code to "gracefully" degrade to working + // but insecure code. + return object; + }; +} + +// ES5 15.2.3.11 +// http://es5.github.com/#x15.2.3.11 +if (!Object.isSealed) { + Object.isSealed = function isSealed(object) { + return false; + }; +} + +// ES5 15.2.3.12 +// http://es5.github.com/#x15.2.3.12 +if (!Object.isFrozen) { + Object.isFrozen = function isFrozen(object) { + return false; + }; +} + +// ES5 15.2.3.13 +// http://es5.github.com/#x15.2.3.13 +if (!Object.isExtensible) { + Object.isExtensible = function isExtensible(object) { + // 1. If Type(O) is not Object throw a TypeError exception. + if (Object(object) === object) { + throw new TypeError(); // TODO message + } + // 2. Return the Boolean value of the [[Extensible]] internal property of O. + var name = ''; + while (owns(object, name)) { + name += '?'; + } + object[name] = true; + var returnValue = owns(object, name); + delete object[name]; + return returnValue; + }; +} + +// ES5 15.2.3.14 +// http://es5.github.com/#x15.2.3.14 +if (!Object.keys) { + // http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation + var hasDontEnumBug = true, + dontEnums = [ + "toString", + "toLocaleString", + "valueOf", + "hasOwnProperty", + "isPrototypeOf", + "propertyIsEnumerable", + "constructor" + ], + dontEnumsLength = dontEnums.length; + + for (var key in {"toString": null}) + hasDontEnumBug = false; + + Object.keys = function keys(object) { + + if ((typeof object != "object" && typeof object != "function") || object === null) + throw new TypeError("Object.keys called on a non-object"); + + var keys = []; + for (var name in object) { + if (owns(object, name)) { + keys.push(name); + } + } + + if (hasDontEnumBug) { + for (var i = 0, ii = dontEnumsLength; i < ii; i++) { + var dontEnum = dontEnums[i]; + if (owns(object, dontEnum)) { + keys.push(dontEnum); + } + } + } + + return keys; + }; + +} + +// +// Date +// ==== +// + +// ES5 15.9.5.43 +// http://es5.github.com/#x15.9.5.43 +// This function returns a String value represent the instance in time +// represented by this Date object. The format of the String is the Date Time +// string format defined in 15.9.1.15. All fields are present in the String. +// The time zone is always UTC, denoted by the suffix Z. If the time value of +// this object is not a finite Number a RangeError exception is thrown. +if (!Date.prototype.toISOString || (new Date(-62198755200000).toISOString().indexOf('-000001') === -1)) { + Date.prototype.toISOString = function toISOString() { + var result, length, value, year; + if (!isFinite(this)) + throw new RangeError; + + // the date time string format is specified in 15.9.1.15. + result = [this.getUTCMonth() + 1, this.getUTCDate(), + this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds()]; + year = this.getUTCFullYear(); + year = (year < 0 ? '-' : (year > 9999 ? '+' : '')) + ('00000' + Math.abs(year)).slice(0 <= year && year <= 9999 ? -4 : -6); + + length = result.length; + while (length--) { + value = result[length]; + // pad months, days, hours, minutes, and seconds to have two digits. + if (value < 10) + result[length] = "0" + value; + } + // pad milliseconds to have three digits. + return year + "-" + result.slice(0, 2).join("-") + "T" + result.slice(2).join(":") + "." + + ("000" + this.getUTCMilliseconds()).slice(-3) + "Z"; + } +} + +// ES5 15.9.4.4 +// http://es5.github.com/#x15.9.4.4 +if (!Date.now) { + Date.now = function now() { + return new Date().getTime(); + }; +} + +// ES5 15.9.5.44 +// http://es5.github.com/#x15.9.5.44 +// This function provides a String representation of a Date object for use by +// JSON.stringify (15.12.3). +if (!Date.prototype.toJSON) { + Date.prototype.toJSON = function toJSON(key) { + // When the toJSON method is called with argument key, the following + // steps are taken: + + // 1. Let O be the result of calling ToObject, giving it the this + // value as its argument. + // 2. Let tv be ToPrimitive(O, hint Number). + // 3. If tv is a Number and is not finite, return null. + // XXX + // 4. Let toISO be the result of calling the [[Get]] internal method of + // O with argument "toISOString". + // 5. If IsCallable(toISO) is false, throw a TypeError exception. + if (typeof this.toISOString != "function") + throw new TypeError(); // TODO message + // 6. Return the result of calling the [[Call]] internal method of + // toISO with O as the this value and an empty argument list. + return this.toISOString(); + + // NOTE 1 The argument is ignored. + + // NOTE 2 The toJSON function is intentionally generic; it does not + // require that its this value be a Date object. Therefore, it can be + // transferred to other kinds of objects for use as a method. However, + // it does require that any such object have a toISOString method. An + // object is free to use the argument key to filter its + // stringification. + }; +} + +// ES5 15.9.4.2 +// http://es5.github.com/#x15.9.4.2 +// based on work shared by Daniel Friesen (dantman) +// http://gist.github.com/303249 +if (Date.parse("+275760-09-13T00:00:00.000Z") !== 8.64e15) { + // XXX global assignment won't work in embeddings that use + // an alternate object for the context. + Date = (function(NativeDate) { + + // Date.length === 7 + var Date = function Date(Y, M, D, h, m, s, ms) { + var length = arguments.length; + if (this instanceof NativeDate) { + var date = length == 1 && String(Y) === Y ? // isString(Y) + // We explicitly pass it through parse: + new NativeDate(Date.parse(Y)) : + // We have to manually make calls depending on argument + // length here + length >= 7 ? new NativeDate(Y, M, D, h, m, s, ms) : + length >= 6 ? new NativeDate(Y, M, D, h, m, s) : + length >= 5 ? new NativeDate(Y, M, D, h, m) : + length >= 4 ? new NativeDate(Y, M, D, h) : + length >= 3 ? new NativeDate(Y, M, D) : + length >= 2 ? new NativeDate(Y, M) : + length >= 1 ? new NativeDate(Y) : + new NativeDate(); + // Prevent mixups with unfixed Date object + date.constructor = Date; + return date; + } + return NativeDate.apply(this, arguments); + }; + + // 15.9.1.15 Date Time String Format. + var isoDateExpression = new RegExp("^" + + "(\\d{4}|[\+\-]\\d{6})" + // four-digit year capture or sign + 6-digit extended year + "(?:-(\\d{2})" + // optional month capture + "(?:-(\\d{2})" + // optional day capture + "(?:" + // capture hours:minutes:seconds.milliseconds + "T(\\d{2})" + // hours capture + ":(\\d{2})" + // minutes capture + "(?:" + // optional :seconds.milliseconds + ":(\\d{2})" + // seconds capture + "(?:\\.(\\d{3}))?" + // milliseconds capture + ")?" + + "(?:" + // capture UTC offset component + "Z|" + // UTC capture + "(?:" + // offset specifier +/-hours:minutes + "([-+])" + // sign capture + "(\\d{2})" + // hours offset capture + ":(\\d{2})" + // minutes offset capture + ")" + + ")?)?)?)?" + + "$"); + + // Copy any custom methods a 3rd party library may have added + for (var key in NativeDate) + Date[key] = NativeDate[key]; + + // Copy "native" methods explicitly; they may be non-enumerable + Date.now = NativeDate.now; + Date.UTC = NativeDate.UTC; + Date.prototype = NativeDate.prototype; + Date.prototype.constructor = Date; + + // Upgrade Date.parse to handle simplified ISO 8601 strings + Date.parse = function parse(string) { + var match = isoDateExpression.exec(string); + if (match) { + match.shift(); // kill match[0], the full match + // parse months, days, hours, minutes, seconds, and milliseconds + for (var i = 1; i < 7; i++) { + // provide default values if necessary + match[i] = +(match[i] || (i < 3 ? 1 : 0)); + // match[1] is the month. Months are 0-11 in JavaScript + // `Date` objects, but 1-12 in ISO notation, so we + // decrement. + if (i == 1) + match[i]--; + } + + // parse the UTC offset component + var minuteOffset = +match.pop(), hourOffset = +match.pop(), sign = match.pop(); + + // compute the explicit time zone offset if specified + var offset = 0; + if (sign) { + // detect invalid offsets and return early + if (hourOffset > 23 || minuteOffset > 59) + return NaN; + + // express the provided time zone offset in minutes. The offset is + // negative for time zones west of UTC; positive otherwise. + offset = (hourOffset * 60 + minuteOffset) * 6e4 * (sign == "+" ? -1 : 1); + } + + // Date.UTC for years between 0 and 99 converts year to 1900 + year + // The Gregorian calendar has a 400-year cycle, so + // to Date.UTC(year + 400, .... ) - 12622780800000 == Date.UTC(year, ...), + // where 12622780800000 - number of milliseconds in Gregorian calendar 400 years + var year = +match[0]; + if (0 <= year && year <= 99) { + match[0] = year + 400; + return NativeDate.UTC.apply(this, match) + offset - 12622780800000; + } + + // compute a new UTC date value, accounting for the optional offset + return NativeDate.UTC.apply(this, match) + offset; + } + return NativeDate.parse.apply(this, arguments); + }; + + return Date; + })(Date); +} + +// +// String +// ====== +// + +// ES5 15.5.4.20 +// http://es5.github.com/#x15.5.4.20 +var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" + + "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" + + "\u2029\uFEFF"; +if (!String.prototype.trim || ws.trim()) { + // http://blog.stevenlevithan.com/archives/faster-trim-javascript + // http://perfectionkills.com/whitespace-deviations/ + ws = "[" + ws + "]"; + var trimBeginRegexp = new RegExp("^" + ws + ws + "*"), + trimEndRegexp = new RegExp(ws + ws + "*$"); + String.prototype.trim = function trim() { + return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, ""); + }; +} + +// +// Util +// ====== +// + +// ES5 9.4 +// http://es5.github.com/#x9.4 +// http://jsperf.com/to-integer +var toInteger = function (n) { + n = +n; + if (n !== n) // isNaN + n = 0; + else if (n !== 0 && n !== (1/0) && n !== -(1/0)) + n = (n > 0 || -1) * Math.floor(Math.abs(n)); + return n; +}; + +var prepareString = "a"[0] != "a", + // ES5 9.9 + // http://es5.github.com/#x9.9 + toObject = function (o) { + if (o == null) { // this matches both null and undefined + throw new TypeError(); // TODO message + } + // If the implementation doesn't support by-index access of + // string characters (ex. IE < 7), split the string + if (prepareString && typeof o == "string" && o) { + return o.split(""); + } + return Object(o); + }; +}); diff --git a/lib/ace/lib/event.js b/lib/ace/lib/event.js new file mode 100644 index 0000000000..0657442521 --- /dev/null +++ b/lib/ace/lib/event.js @@ -0,0 +1,315 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var keys = require("./keys"); +var useragent = require("./useragent"); +var dom = require("./dom"); + +exports.addListener = function(elem, type, callback) { + if (elem.addEventListener) { + return elem.addEventListener(type, callback, false); + } + if (elem.attachEvent) { + var wrapper = function() { + callback(window.event); + }; + callback._wrapper = wrapper; + elem.attachEvent("on" + type, wrapper); + } +}; + +exports.removeListener = function(elem, type, callback) { + if (elem.removeEventListener) { + return elem.removeEventListener(type, callback, false); + } + if (elem.detachEvent) { + elem.detachEvent("on" + type, callback._wrapper || callback); + } +}; + +/* +* Prevents propagation and clobbers the default action of the passed event +*/ +exports.stopEvent = function(e) { + exports.stopPropagation(e); + exports.preventDefault(e); + return false; +}; + +exports.stopPropagation = function(e) { + if (e.stopPropagation) + e.stopPropagation(); + else + e.cancelBubble = true; +}; + +exports.preventDefault = function(e) { + if (e.preventDefault) + e.preventDefault(); + else + e.returnValue = false; +}; + +/* + * @return {Number} 0 for left button, 1 for middle button, 2 for right button + */ +exports.getButton = function(e) { + if (e.type == "dblclick") + return 0; + if (e.type == "contextmenu" || (e.ctrlKey && useragent.isMac)) + return 2; + + // DOM Event + if (e.preventDefault) { + return e.button; + } + // old IE + else { + return {1:0, 2:2, 4:1}[e.button]; + } +}; + +if (document.documentElement.setCapture) { + exports.capture = function(el, eventHandler, releaseCaptureHandler) { + var called = false; + function onReleaseCapture(e) { + eventHandler(e); + + if (!called) { + called = true; + releaseCaptureHandler(e); + } + + exports.removeListener(el, "mousemove", eventHandler); + exports.removeListener(el, "mouseup", onReleaseCapture); + exports.removeListener(el, "losecapture", onReleaseCapture); + + el.releaseCapture(); + } + + exports.addListener(el, "mousemove", eventHandler); + exports.addListener(el, "mouseup", onReleaseCapture); + exports.addListener(el, "losecapture", onReleaseCapture); + el.setCapture(); + }; +} +else { + exports.capture = function(el, eventHandler, releaseCaptureHandler) { + function onMouseUp(e) { + eventHandler && eventHandler(e); + releaseCaptureHandler && releaseCaptureHandler(e); + + document.removeEventListener("mousemove", eventHandler, true); + document.removeEventListener("mouseup", onMouseUp, true); + + e.stopPropagation(); + } + + document.addEventListener("mousemove", eventHandler, true); + document.addEventListener("mouseup", onMouseUp, true); + }; +} + +exports.addMouseWheelListener = function(el, callback) { + var factor = 8; + var listener = function(e) { + if (e.wheelDelta !== undefined) { + if (e.wheelDeltaX !== undefined) { + e.wheelX = -e.wheelDeltaX / factor; + e.wheelY = -e.wheelDeltaY / factor; + } else { + e.wheelX = 0; + e.wheelY = -e.wheelDelta / factor; + } + } + else { + if (e.axis && e.axis == e.HORIZONTAL_AXIS) { + e.wheelX = (e.detail || 0) * 5; + e.wheelY = 0; + } else { + e.wheelX = 0; + e.wheelY = (e.detail || 0) * 5; + } + } + callback(e); + }; + exports.addListener(el, "DOMMouseScroll", listener); + exports.addListener(el, "mousewheel", listener); +}; + +exports.addMultiMouseDownListener = function(el, timeouts, eventHandler, callbackName) { + var clicks = 0; + var startX, startY, timer; + var eventNames = { + 2: "dblclick", + 3: "tripleclick", + 4: "quadclick" + }; + + exports.addListener(el, "mousedown", function(e) { + if (exports.getButton(e) != 0) { + clicks = 0; + } else { + var isNewClick = Math.abs(e.clientX - startX) > 5 || Math.abs(e.clientY - startY) > 5; + + if (!timer || isNewClick) + clicks = 0; + + clicks += 1; + + if (timer) + clearTimeout(timer) + timer = setTimeout(function() {timer = null}, timeouts[clicks - 1] || 600); + } + if (clicks == 1) { + startX = e.clientX; + startY = e.clientY; + } + + eventHandler[callbackName]("mousedown", e); + + if (clicks > 4) + clicks = 0; + else if (clicks > 1) + return eventHandler[callbackName](eventNames[clicks], e); + }); + + if (useragent.isOldIE) { + exports.addListener(el, "dblclick", function(e) { + clicks = 2; + if (timer) + clearTimeout(timer); + timer = setTimeout(function() {timer = null}, timeouts[clicks - 1] || 600); + eventHandler[callbackName]("mousedown", e); + eventHandler[callbackName](eventNames[clicks], e); + }); + } +}; + +function normalizeCommandKeys(callback, e, keyCode) { + var hashId = 0; + if ((useragent.isOpera && !("KeyboardEvent" in window)) && useragent.isMac) { + hashId = 0 | (e.metaKey ? 1 : 0) | (e.altKey ? 2 : 0) + | (e.shiftKey ? 4 : 0) | (e.ctrlKey ? 8 : 0); + } else { + hashId = 0 | (e.ctrlKey ? 1 : 0) | (e.altKey ? 2 : 0) + | (e.shiftKey ? 4 : 0) | (e.metaKey ? 8 : 0); + } + + if (keyCode in keys.MODIFIER_KEYS) { + switch (keys.MODIFIER_KEYS[keyCode]) { + case "Alt": + hashId = 2; + break; + case "Shift": + hashId = 4; + break; + case "Ctrl": + hashId = 1; + break; + default: + hashId = 8; + break; + } + keyCode = 0; + } + + if (hashId & 8 && (keyCode == 91 || keyCode == 93)) { + keyCode = 0; + } + + // If there is no hashID and the keyCode is not a function key, then + // we don't call the callback as we don't handle a command key here + // (it's a normal key/character input). + if (!hashId && !(keyCode in keys.FUNCTION_KEYS) && !(keyCode in keys.PRINTABLE_KEYS)) { + return false; + } + return callback(e, hashId, keyCode); +} + +exports.addCommandKeyListener = function(el, callback) { + var addListener = exports.addListener; + if (useragent.isOldGecko || (useragent.isOpera && !("KeyboardEvent" in window))) { + // Old versions of Gecko aka. Firefox < 4.0 didn't repeat the keydown + // event if the user pressed the key for a longer time. Instead, the + // keydown event was fired once and later on only the keypress event. + // To emulate the 'right' keydown behavior, the keyCode of the initial + // keyDown event is stored and in the following keypress events the + // stores keyCode is used to emulate a keyDown event. + var lastKeyDownKeyCode = null; + addListener(el, "keydown", function(e) { + lastKeyDownKeyCode = e.keyCode; + }); + addListener(el, "keypress", function(e) { + return normalizeCommandKeys(callback, e, lastKeyDownKeyCode); + }); + } else { + var lastDown = null; + + addListener(el, "keydown", function(e) { + lastDown = e.keyIdentifier || e.keyCode; + return normalizeCommandKeys(callback, e, e.keyCode); + }); + } +}; + +if (window.postMessage && !useragent.isOldIE) { + var postMessageId = 1; + exports.nextTick = function(callback, win) { + win = win || window; + var messageName = "zero-timeout-message-" + postMessageId; + exports.addListener(win, "message", function listener(e) { + if (e.data == messageName) { + exports.stopPropagation(e); + exports.removeListener(win, "message", listener); + callback(); + } + }); + win.postMessage(messageName, "*"); + }; +} + + +exports.nextFrame = window.requestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.webkitRequestAnimationFrame; + +if (exports.nextFrame) + exports.nextFrame = exports.nextFrame.bind(window); +else + exports.nextFrame = function(callback) { + setTimeout(callback, 17); + }; +}); diff --git a/lib/ace/lib/event_emitter.js b/lib/ace/lib/event_emitter.js new file mode 100644 index 0000000000..5f4bec86d5 --- /dev/null +++ b/lib/ace/lib/event_emitter.js @@ -0,0 +1,114 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var EventEmitter = {}; + +EventEmitter._emit = +EventEmitter._dispatchEvent = function(eventName, e) { + this._eventRegistry = this._eventRegistry || {}; + this._defaultHandlers = this._defaultHandlers || {}; + + var listeners = this._eventRegistry[eventName] || []; + var defaultHandler = this._defaultHandlers[eventName]; + if (!listeners.length && !defaultHandler) + return; + + if (typeof e != "object" || !e) + e = {}; + + if (!e.type) + e.type = eventName; + + if (!e.stopPropagation) { + e.stopPropagation = function() { + this.propagationStopped = true; + }; + } + + if (!e.preventDefault) { + e.preventDefault = function() { + this.defaultPrevented = true; + }; + } + + for (var i=0; i + * Provides an augmented, extensible, cross-browser implementation of regular expressions, + * including support for additional syntax, flags, and methods + */ + +define(function(require, exports, module) { +"use strict"; + + //--------------------------------- + // Private variables + //--------------------------------- + + var real = { + exec: RegExp.prototype.exec, + test: RegExp.prototype.test, + match: String.prototype.match, + replace: String.prototype.replace, + split: String.prototype.split + }, + compliantExecNpcg = real.exec.call(/()??/, "")[1] === undefined, // check `exec` handling of nonparticipating capturing groups + compliantLastIndexIncrement = function () { + var x = /^/g; + real.test.call(x, ""); + return !x.lastIndex; + }(); + + if (compliantLastIndexIncrement && compliantExecNpcg) + return; + + //--------------------------------- + // Overriden native methods + //--------------------------------- + + // Adds named capture support (with backreferences returned as `result.name`), and fixes two + // cross-browser issues per ES3: + // - Captured values for nonparticipating capturing groups should be returned as `undefined`, + // rather than the empty string. + // - `lastIndex` should not be incremented after zero-length matches. + RegExp.prototype.exec = function (str) { + var match = real.exec.apply(this, arguments), + name, r2; + if ( typeof(str) == 'string' && match) { + // Fix browsers whose `exec` methods don't consistently return `undefined` for + // nonparticipating capturing groups + if (!compliantExecNpcg && match.length > 1 && indexOf(match, "") > -1) { + r2 = RegExp(this.source, real.replace.call(getNativeFlags(this), "g", "")); + // Using `str.slice(match.index)` rather than `match[0]` in case lookahead allowed + // matching due to characters outside the match + real.replace.call(str.slice(match.index), r2, function () { + for (var i = 1; i < arguments.length - 2; i++) { + if (arguments[i] === undefined) + match[i] = undefined; + } + }); + } + // Attach named capture properties + if (this._xregexp && this._xregexp.captureNames) { + for (var i = 1; i < match.length; i++) { + name = this._xregexp.captureNames[i - 1]; + if (name) + match[name] = match[i]; + } + } + // Fix browsers that increment `lastIndex` after zero-length matches + if (!compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index)) + this.lastIndex--; + } + return match; + }; + + // Don't override `test` if it won't change anything + if (!compliantLastIndexIncrement) { + // Fix browser bug in native method + RegExp.prototype.test = function (str) { + // Use the native `exec` to skip some processing overhead, even though the overriden + // `exec` would take care of the `lastIndex` fix + var match = real.exec.call(this, str); + // Fix browsers that increment `lastIndex` after zero-length matches + if (match && this.global && !match[0].length && (this.lastIndex > match.index)) + this.lastIndex--; + return !!match; + }; + } + + //--------------------------------- + // Private helper functions + //--------------------------------- + + function getNativeFlags (regex) { + return (regex.global ? "g" : "") + + (regex.ignoreCase ? "i" : "") + + (regex.multiline ? "m" : "") + + (regex.extended ? "x" : "") + // Proposed for ES4; included in AS3 + (regex.sticky ? "y" : ""); + } + + function indexOf (array, item, from) { + if (Array.prototype.indexOf) // Use the native array method if available + return array.indexOf(item, from); + for (var i = from || 0; i < array.length; i++) { + if (array[i] === item) + return i; + } + return -1; + } + +}); diff --git a/lib/ace/lib/useragent.js b/lib/ace/lib/useragent.js new file mode 100644 index 0000000000..14f0ee9b94 --- /dev/null +++ b/lib/ace/lib/useragent.js @@ -0,0 +1,102 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +/* + * I hate doing this, but we need some way to determine if the user is on a Mac + * The reason is that users have different expectations of their key combinations. + * + * Take copy as an example, Mac people expect to use CMD or APPLE + C + * Windows folks expect to use CTRL + C + */ +exports.OS = { + LINUX: "LINUX", + MAC: "MAC", + WINDOWS: "WINDOWS" +}; + +/* + * Return an exports.OS constant + */ +exports.getOS = function() { + if (exports.isMac) { + return exports.OS.MAC; + } else if (exports.isLinux) { + return exports.OS.LINUX; + } else { + return exports.OS.WINDOWS; + } +}; + +// this can be called in non browser environments (e.g. from ace/requirejs/text) +if (typeof navigator != "object") + return; + +var os = (navigator.platform.match(/mac|win|linux/i) || ["other"])[0].toLowerCase(); +var ua = navigator.userAgent; + +// Is the user using a browser that identifies itself as Windows +exports.isWin = (os == "win"); + +// Is the user using a browser that identifies itself as Mac OS +exports.isMac = (os == "mac"); + +// Is the user using a browser that identifies itself as Linux +exports.isLinux = (os == "linux"); + +exports.isIE = + navigator.appName == "Microsoft Internet Explorer" + && parseFloat(navigator.userAgent.match(/MSIE ([0-9]+[\.0-9]+)/)[1]); + +exports.isOldIE = exports.isIE && exports.isIE < 9; + +// Is this Firefox or related? +exports.isGecko = exports.isMozilla = window.controllers && window.navigator.product === "Gecko"; + +// oldGecko == rev < 2.0 +exports.isOldGecko = exports.isGecko && parseInt((navigator.userAgent.match(/rv\:(\d+)/)||[])[1], 10) < 4; + +// Is this Opera +exports.isOpera = window.opera && Object.prototype.toString.call(window.opera) == "[object Opera]"; + +// Is the user using a browser that identifies itself as WebKit +exports.isWebKit = parseFloat(ua.split("WebKit/")[1]) || undefined; + +exports.isChrome = parseFloat(ua.split(" Chrome/")[1]) || undefined; + +exports.isAIR = ua.indexOf("AdobeAIR") >= 0; + +exports.isIPad = ua.indexOf("iPad") >= 0; + +exports.isTouchPad = ua.indexOf("TouchPad") >= 0; + +}); diff --git a/lib/ace/mode/_test/package.json b/lib/ace/mode/_test/package.json new file mode 100644 index 0000000000..3fdc706de7 --- /dev/null +++ b/lib/ace/mode/_test/package.json @@ -0,0 +1,8 @@ +{ + "name": "ace-mode-creator", + "version": "0.1.0", + "dependencies": { + "connect": "", + "socket.io": "" + } +} \ No newline at end of file diff --git a/lib/ace/mode/_test/test_highlight_rules.js b/lib/ace/mode/_test/test_highlight_rules.js new file mode 100644 index 0000000000..6c28ba39de --- /dev/null +++ b/lib/ace/mode/_test/test_highlight_rules.js @@ -0,0 +1,144 @@ +var fs = require("fs"); +if (!fs.existsSync) + fs.existsSync = require("path").existsSync; + +require("amd-loader"); + +var cwd = __dirname + "/"; + +function generateTestData() { + var root = Array(5).join("../") + "/demo/kitchen-sink/docs"; + var docs = fs.readdirSync(cwd + root); + var specialDocs = fs.readdirSync(cwd); + var modes = fs.readdirSync(cwd + "../").filter(function(x){ + return /^\w+_highlight_rules.js$/.test(x); + }).map(function(x) { + return x.replace(/_highlight_rules.js$/, ""); + }); + + console.log("Docs:", docs); + console.log("Modes:", modes); + + docs.forEach(function(docName) { + var p = docName.toLowerCase().split("."); + if (!p[1]) + return; + var modeName; + if (modes.indexOf(p[0]) != -1) + modeName = p[0]; + else if (modes.indexOf(p[1]) != -1) + modeName = p[1]; + else + modeName = {"txt": "text", cpp: "c_cpp"}[p[1]]; + + var filePath = "text_" + modeName + ".txt"; + if (specialDocs.indexOf(filePath) == -1) { + filePath = root + "/" + docName; + } + + var text = fs.readFileSync(cwd + filePath, "utf8"); + try { + var Mode = require("../" + modeName).Mode; + } catch(e) { + console.warn("Can't load mode :" + modeName, e); + return; + } + var tokenizer = new Mode().getTokenizer(); + + var state = "start"; + var data = text.split(/\n|\r|\r\n/).map(function(line) { + var tokens = tokenizer.getLineTokens(line, state); + state = tokens.state; + tokens = tokens.tokens; + return { + state: state, + data: tokens.map(function(x) {return [x.type, x.value]}) + }; + }); + var jsonStr = JSON.stringify(data, null, 1); + jsonStr = jsonStr.replace(/\n {4}/g, " ").replace(/\n {3}]/g, " ]"); + fs.writeFileSync(cwd + "tokens_" + modeName + ".json", jsonStr, "utf8"); + }); +} + +function test(startAt) { + var docs = fs.readdirSync(cwd).filter(function(x) { + return /^tokens_\w+.json$/.test(x); + }); + if (startAt && startAt > 1) + docs = docs.slice(startAt - 1); + docs.forEach(function(x, i) { + var modeName = x.match(/tokens_(.*).json/)[1]; + + console.log(padNumber(i+1, 3) + ") testing: \u001b[33m" + modeName + "\u001b[0m"); + + var text = fs.readFileSync(cwd + x, "utf8"); + var data = JSON.parse(text); + var Mode = require("../" + modeName).Mode; + var tokenizer = new Mode().getTokenizer(); + + var state = "start"; + data.forEach(function(lineData) { + lineData.values = []; + lineData.types = []; + lineData.data.forEach(function(x) { + lineData.types.push(x[0]); + lineData.values.push(x[1]); + }); + + var line = lineData.values.join(""); + + var tokens = tokenizer.getLineTokens(line, state); + var values = tokens.tokens.map(function(x) {return x.value;}); + var types = tokens.tokens.map(function(x) {return x.type;}); + + var success = true; + testEqual([ + lineData.state, tokens.state, + lineData.types, types, + lineData.values, values]); + + state = lineData.state; + }); + }); + + console.log("\u001b[32m" + "all ok" + "\u001b[0m"); + + function testEqual(a) { + var err; + if (a[0] !== a[1]) { + console.log(a[0],a[1]); + err = 1; + } + + if ( a[2] + "" !== a[3] + "" || a[4] + "" !== a[5] + "") { + arrayDiff(a[2],a[3]); + arrayDiff(a[4],a[5]); + err = 1; + } + if (err) { + throw "error"; + } + } + + function arrayDiff(a1, a2) { + var l = Math.max(a1.length, a2.length); + var out = []; + for (var i = 0; i < l; i++) { + out.push("\n", padNumber(i+1, 3), ") "); + if (a1[i] !== a2[i]) + out.push("\u001b[31m", a1[i], " != ", a2[i], "\u001b[0m"); + else + out.push(a1[i]); + } + console.log(out.join("")); + } + function padNumber(num, digits) { + return (" " + num).slice(-digits); + } +} + +if (process.argv[2] == "gen") + generateTestData(process.argv.splice(3)); +else + test(parseInt(process.argv[2],10) || 0); diff --git a/lib/ace/mode/_test/text_javascript.txt b/lib/ace/mode/_test/text_javascript.txt new file mode 100644 index 0000000000..a4b5095a47 --- /dev/null +++ b/lib/ace/mode/_test/text_javascript.txt @@ -0,0 +1,52 @@ +function foo(items, nada) { + for (var i=0; i" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword.control", "using" ], + [ "text", " " ], + [ "keyword.operator", "namespace" ], + [ "text", " " ], + [ "identifier", "std" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "storage.type", "int" ], + [ "text", " " ], + [ "entity.name.function", "main" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "storage.type", "int" ], + [ "text", " " ], + [ "identifier", "a" ], + [ "punctuation.operator", "," ], + [ "text", " " ], + [ "identifier", "b" ], + [ "keyword.operator", "=" ], + [ "constant.numeric", "3" ], + [ "punctuation.operator", ";" ], + [ "text", " " ], + [ "comment", "/*" ], + [ "comment", " foobar */" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "a" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "identifier", "b" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "a" ], + [ "keyword.operator", "+" ], + [ "keyword.operator", "=" ], + [ "constant.numeric", "2" ], + [ "punctuation.operator", ";" ], + [ "text", " " ], + [ "comment", "// equivalent to a=a+2" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "cout" ], + [ "text", " " ], + [ "keyword.operator", "<" ], + [ "keyword.operator", "<" ], + [ "text", " " ], + [ "identifier", "a" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword.control", "return" ], + [ "text", " " ], + [ "constant.numeric", "0" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_clojure.json b/lib/ace/mode/_test/tokens_clojure.json new file mode 100644 index 0000000000..e83b3d89ae --- /dev/null +++ b/lib/ace/mode/_test/tokens_clojure.json @@ -0,0 +1,248 @@ +[ + { + "state": "start", + "data": [ + [ "keyword", "(" ], + [ "support.function", "defn" ], + [ "text", " " ], + [ "identifier", "parting" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "string", "\"returns a String parting in a given language" ], + [ "string", "\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "(" ], + [ "keyword", "[" ], + [ "keyword", "]" ], + [ "text", " " ], + [ "keyword", "(" ], + [ "identifier", "parting" ], + [ "text", " " ], + [ "string", "\"World" ], + [ "string", "\"" ], + [ "keyword", ")" ], + [ "keyword", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "(" ], + [ "keyword", "[" ], + [ "support.function", "name" ], + [ "keyword", "]" ], + [ "text", " " ], + [ "keyword", "(" ], + [ "identifier", "parting" ], + [ "text", " " ], + [ "support.function", "name" ], + [ "text", " " ], + [ "string", "\"en" ], + [ "string", "\"" ], + [ "keyword", ")" ], + [ "keyword", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "(" ], + [ "keyword", "[" ], + [ "support.function", "name" ], + [ "text", " " ], + [ "identifier", "language" ], + [ "keyword", "]" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "comment", "; condp is similar to a case statement in other languages." ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "comment", "; It is described in more detail later." ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "comment", "; It is used here to take different actions based on whether the" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "comment", "; parameter \"language\" is set to \"en\", \"es\" or something else." ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "(" ], + [ "support.function", "condp" ], + [ "text", " " ], + [ "constant.language", "=" ], + [ "text", " " ], + [ "identifier", "language" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "string", "\"en" ], + [ "string", "\"" ], + [ "text", " " ], + [ "keyword", "(" ], + [ "support.function", "str" ], + [ "text", " " ], + [ "string", "\"Goodbye, " ], + [ "string", "\"" ], + [ "text", " " ], + [ "support.function", "name" ], + [ "keyword", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "string", "\"es" ], + [ "string", "\"" ], + [ "text", " " ], + [ "keyword", "(" ], + [ "support.function", "str" ], + [ "text", " " ], + [ "string", "\"Adios, " ], + [ "string", "\"" ], + [ "text", " " ], + [ "support.function", "name" ], + [ "keyword", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "(" ], + [ "keyword", "throw" ], + [ "text", " " ], + [ "keyword", "(" ], + [ "identifier", "IllegalArgumentException" ], + [ "text", "." ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "(" ], + [ "support.function", "str" ], + [ "text", " " ], + [ "string", "\"unsupported language " ], + [ "string", "\"" ], + [ "text", " " ], + [ "identifier", "language" ], + [ "keyword", ")" ], + [ "keyword", ")" ], + [ "keyword", ")" ], + [ "keyword", ")" ], + [ "keyword", ")" ], + [ "keyword", ")" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "(" ], + [ "support.function", "println" ], + [ "text", " " ], + [ "keyword", "(" ], + [ "identifier", "parting" ], + [ "keyword", ")" ], + [ "keyword", ")" ], + [ "text", " " ], + [ "comment", "; -> Goodbye, World" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "(" ], + [ "support.function", "println" ], + [ "text", " " ], + [ "keyword", "(" ], + [ "identifier", "parting" ], + [ "text", " " ], + [ "string", "\"Mark" ], + [ "string", "\"" ], + [ "keyword", ")" ], + [ "keyword", ")" ], + [ "text", " " ], + [ "comment", "; -> Goodbye, Mark" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "(" ], + [ "support.function", "println" ], + [ "text", " " ], + [ "keyword", "(" ], + [ "identifier", "parting" ], + [ "text", " " ], + [ "string", "\"Mark" ], + [ "string", "\"" ], + [ "text", " " ], + [ "string", "\"es" ], + [ "string", "\"" ], + [ "keyword", ")" ], + [ "keyword", ")" ], + [ "text", " " ], + [ "comment", "; -> Adios, Mark" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "(" ], + [ "support.function", "println" ], + [ "text", " " ], + [ "keyword", "(" ], + [ "identifier", "parting" ], + [ "text", " " ], + [ "string", "\"Mark" ], + [ "string", "\"" ], + [ "text", ", " ], + [ "string", "\"xy" ], + [ "string", "\"" ], + [ "keyword", ")" ], + [ "keyword", ")" ], + [ "text", " " ], + [ "comment", "; -> java.lang.IllegalArgumentException: unsupported language xy" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_coffee.json b/lib/ace/mode/_test/tokens_coffee.json new file mode 100644 index 0000000000..e8c97baacf --- /dev/null +++ b/lib/ace/mode/_test/tokens_coffee.json @@ -0,0 +1,188 @@ +[ + { + "state": "start", + "data": [ + [ "comment", "#!/usr/bin/env coffee" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "try" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "throw" ], + [ "text", " " ], + [ "language.support.class", "URIError" ], + [ "text", " " ], + [ "language.support.function", "decodeURI" ], + [ "paren.lparen", "(" ], + [ "constant.numeric", "0xC0ffee" ], + [ "text", " " ], + [ "keyword.operator", "*" ], + [ "text", " " ], + [ "constant.numeric", "123456.7e-8" ], + [ "text", " " ], + [ "keyword.operator", "/" ], + [ "text", " " ], + [ "constant.numeric", ".9" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "catch" ], + [ "text", " " ], + [ "identifier", "e" ] + ] + }, + { + "state": "qdoc", + "data": [ + [ "text", " " ], + [ "identifier", "console" ], + [ "identifier", ".log" ], + [ "text", " " ], + [ "string", "'qstring'" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "text", " " ], + [ "string", "\"qqstring\"" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "text", " " ], + [ "string", "'''" ] + ] + }, + { + "state": "qdoc", + "data": [ + [ "string", " qdoc" ] + ] + }, + { + "state": "qqdoc", + "data": [ + [ "string", " '''" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "text", " " ], + [ "string", "\"\"\"" ] + ] + }, + { + "state": "qqdoc", + "data": [ + [ "string", " qqdoc" ] + ] + }, + { + "state": "start", + "data": [ + [ "string", " \"\"\"" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "do" ], + [ "text", " " ], + [ "keyword.operator", "->" ] + ] + }, + { + "state": "comment", + "data": [ + [ "text", " " ], + [ "comment", "###" ] + ] + }, + { + "state": "comment", + "data": [ + [ "comment", " herecomment" ] + ] + }, + { + "state": "start", + "data": [ + [ "comment", " ###" ] + ] + }, + { + "state": "heregex", + "data": [ + [ "text", " " ], + [ "identifier", "re" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "string.regex", "/regex/imgy" ], + [ "identifier", ".test" ], + [ "text", " " ], + [ "string.regex", "///" ] + ] + }, + { + "state": "heregex", + "data": [ + [ "comment.regex", " " ], + [ "string.regex", "heregex" ], + [ "comment.regex", " # comment" ] + ] + }, + { + "state": "start", + "data": [ + [ "string.regex", " ///imgy" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "this" ], + [ "text", " " ], + [ "keyword", "isnt" ], + [ "punctuation.operator", ":" ], + [ "text", " " ], + [ "string", "`just JavaScript`" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "constant.language", "undefined" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ] + ] + }, + { + "state": "start", + "data": [ + [ "identifier", "sentence" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "string", "\"#{ 22 / 7 } is a decent approximation of π\"" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_coldfusion.json b/lib/ace/mode/_test/tokens_coldfusion.json new file mode 100644 index 0000000000..2c2a602c3a --- /dev/null +++ b/lib/ace/mode/_test/tokens_coldfusion.json @@ -0,0 +1,41 @@ +[ + { + "state": "start", + "data": [ + [ "comment", "" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "cfset" ], + [ "text", " " ], + [ "entity.other.attribute-name", "welcome" ], + [ "keyword.operator", "=" ], + [ "string", "\"Hello World!\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "cfoutput" ], + [ "meta.tag", ">" ], + [ "text", "#welcome#" ], + [ "meta.tag", "" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_csharp.json b/lib/ace/mode/_test/tokens_csharp.json new file mode 100644 index 0000000000..167fdbe874 --- /dev/null +++ b/lib/ace/mode/_test/tokens_csharp.json @@ -0,0 +1,42 @@ +[ + { + "state": "start", + "data": [ + [ "keyword", "public" ], + [ "text", " " ], + [ "keyword", "void" ], + [ "text", " " ], + [ "identifier", "HelloWorld" ], + [ "paren.lparen", "(" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "comment", "//Say Hello!" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "Console" ], + [ "punctuation.operator", "." ], + [ "identifier", "WriteLine" ], + [ "paren.lparen", "(" ], + [ "string", "\"Hello World\"" ], + [ "paren.rparen", ")" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_css.json b/lib/ace/mode/_test/tokens_css.json new file mode 100644 index 0000000000..a7b607ccf7 --- /dev/null +++ b/lib/ace/mode/_test/tokens_css.json @@ -0,0 +1,231 @@ +[ + { + "state": "ruleset", + "data": [ + [ "variable", ".text-layer" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "ruleset", + "data": [ + [ "text", " " ], + [ "support.type", "font-family" ], + [ "text", ": Monaco, " ], + [ "string", "\"Courier New\"" ], + [ "text", ", " ], + [ "support.constant.fonts", "monospace" ], + [ "text", ";" ] + ] + }, + { + "state": "ruleset", + "data": [ + [ "text", " " ], + [ "support.type", "font-size" ], + [ "text", ": " ], + [ "constant.numeric", "12" ], + [ "keyword", "px" ], + [ "text", ";" ] + ] + }, + { + "state": "ruleset", + "data": [ + [ "text", " " ], + [ "support.type", "cursor" ], + [ "text", ": " ], + [ "support.constant", "text" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "ruleset", + "data": [ + [ "variable", ".blinker" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "ruleset", + "data": [ + [ "text", " " ], + [ "support.type", "animation-duration" ], + [ "text", ": " ], + [ "constant.numeric", "1" ], + [ "keyword", "s" ], + [ "text", ";" ] + ] + }, + { + "state": "ruleset", + "data": [ + [ "text", " " ], + [ "support.type", "animation-name" ], + [ "text", ": blink;" ] + ] + }, + { + "state": "ruleset", + "data": [ + [ "text", " " ], + [ "support.type", "animation-iteration-count" ], + [ "text", ": infinite;" ] + ] + }, + { + "state": "ruleset", + "data": [ + [ "text", " " ], + [ "support.type", "animation-direction" ], + [ "text", ": alternate;" ] + ] + }, + { + "state": "ruleset", + "data": [ + [ "text", " " ], + [ "support.type", "animation-timing-function" ], + [ "text", ": " ], + [ "support.constant", "linear" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "media", + "data": [ + [ "string", "@keyframes blink {" ] + ] + }, + { + "state": "media_ruleset", + "data": [ + [ "text", " " ], + [ "constant", "0" ], + [ "text", "% " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "media_ruleset", + "data": [ + [ "text", " " ], + [ "support.type", "opacity" ], + [ "text", ": " ], + [ "constant.numeric", "0" ], + [ "text", ";" ] + ] + }, + { + "state": "media", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "media_ruleset", + "data": [ + [ "text", " " ], + [ "constant", "40" ], + [ "text", "% " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "media_ruleset", + "data": [ + [ "text", " " ], + [ "support.type", "opacity" ], + [ "text", ": " ], + [ "constant.numeric", "0" ], + [ "text", ";" ] + ] + }, + { + "state": "media", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "media_ruleset", + "data": [ + [ "text", " " ], + [ "constant", "40" ], + [ "variable", ".5" ], + [ "text", "% " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "media_ruleset", + "data": [ + [ "text", " " ], + [ "support.type", "opacity" ], + [ "text", ": " ], + [ "constant.numeric", "1" ] + ] + }, + { + "state": "media", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "media_ruleset", + "data": [ + [ "text", " " ], + [ "constant", "100" ], + [ "text", "% " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "media_ruleset", + "data": [ + [ "text", " " ], + [ "support.type", "opacity" ], + [ "text", ": " ], + [ "constant.numeric", "1" ] + ] + }, + { + "state": "media", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "string", "}" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_diff.json b/lib/ace/mode/_test/tokens_diff.json new file mode 100644 index 0000000000..fa28d05d8c --- /dev/null +++ b/lib/ace/mode/_test/tokens_diff.json @@ -0,0 +1,732 @@ +[ + { + "state": "start", + "data": [ + [ "variable", "diff" ], + [ "variable", " --git" ], + [ "keyword", " a/lib/ace/edit_session.js" ], + [ "variable", " b/lib/ace/edit_session.js" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "variable", "index 23fc3fc..ed3b273 100644" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "constant.numeric", "---" ], + [ "meta.tag", " a/lib/ace/edit_session.js" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "constant.numeric", "+++" ], + [ "meta.tag", " b/lib/ace/edit_session.js" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "constant", "@@" ], + [ "constant.numeric", " -51,6 +51,7 " ], + [ "constant", "@@" ], + [ "comment.doc.tag", " var TextMode = require(\"./mode/text\").Mode;" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", " var Range = require(\"./range\").Range;" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", " var Document = require(\"./document\").Document;" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", " var BackgroundTokenizer = require(\"./background_tokenizer\").BackgroundTokenizer;" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.constant", "+" ], + [ "text", "var SearchHighlight = require(\"./search_highlight\").SearchHighlight;" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", " /**" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", " * class EditSession" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "constant", "@@" ], + [ "constant.numeric", " -307,6 +308,13 " ], + [ "constant", "@@" ], + [ "comment.doc.tag", " var EditSession = function(text, mode) {" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", " return token;" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", " };" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.constant", "+" ], + [ "text", " this.highlight = function(re) {" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.constant", "+" ], + [ "text", " if (!this.$searchHighlight) {" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.constant", "+" ], + [ "text", " var highlight = new SearchHighlight(null, \"ace_selected-word\", \"text\");" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.constant", "+" ], + [ "text", " this.$searchHighlight = this.addDynamicMarker(highlight);" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.constant", "+" ], + [ "text", " }" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.constant", "+" ], + [ "text", " this.$searchHighlight.setRegexp(re);" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.constant", "+" ], + [ "text", " }" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", " /**" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", " * EditSession.setUndoManager(undoManager)" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", " * - undoManager (UndoManager): The new undo manager" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "constant", "@@" ], + [ "constant.numeric", " -556,7 +564,8 " ], + [ "constant", "@@" ], + [ "comment.doc.tag", " var EditSession = function(text, mode) {" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", " type : type || \"line\"," ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", " renderer: typeof type == \"function\" ? type : null," ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", " clazz : clazz," ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.function", "-" ], + [ "string", " inFront: !!inFront" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.constant", "+" ], + [ "text", " inFront: !!inFront," ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.constant", "+" ], + [ "text", " id: id" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", " }" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", " if (inFront) {" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "variable", "diff" ], + [ "variable", " --git" ], + [ "keyword", " a/lib/ace/editor.js" ], + [ "variable", " b/lib/ace/editor.js" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "variable", "index 834e603..b27ec73 100644" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "constant.numeric", "---" ], + [ "meta.tag", " a/lib/ace/editor.js" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "constant.numeric", "+++" ], + [ "meta.tag", " b/lib/ace/editor.js" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "constant", "@@" ], + [ "constant.numeric", " -494,7 +494,7 " ], + [ "constant", "@@" ], + [ "comment.doc.tag", " var Editor = function(renderer, session) {" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", " * Emitted when a selection has changed." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", " **/" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", " this.onSelectionChange = function(e) {" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.function", "-" ], + [ "string", " var session = this.getSession();" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.constant", "+" ], + [ "text", " var session = this.session;" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", " if (session.$selectionMarker) {" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", " session.removeMarker(session.$selectionMarker);" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "constant", "@@" ], + [ "constant.numeric", " -509,12 +509,40 " ], + [ "constant", "@@" ], + [ "comment.doc.tag", " var Editor = function(renderer, session) {" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", " this.$updateHighlightActiveLine();" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", " }" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.function", "-" ], + [ "string", " var self = this;" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.function", "-" ], + [ "string", " if (this.$highlightSelectedWord && !this.$wordHighlightTimer)" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.function", "-" ], + [ "string", " this.$wordHighlightTimer = setTimeout(function() {" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.function", "-" ], + [ "string", " self.session.$mode.highlightSelection(self);" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.function", "-" ], + [ "string", " self.$wordHighlightTimer = null;" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.function", "-" ], + [ "string", " }, 30, this);" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.constant", "+" ], + [ "text", " var re = this.$highlightSelectedWord && this.$getSelectionHighLightRegexp()" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", " };" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "variable", "diff" ], + [ "variable", " --git" ], + [ "keyword", " a/lib/ace/search_highlight.js" ], + [ "variable", " b/lib/ace/search_highlight.js" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "invisible", "new file mode 100644" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "variable", "index 0000000..b2df779" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "constant.numeric", "---" ], + [ "meta.tag", " /dev/null" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "constant.numeric", "+++" ], + [ "meta.tag", " b/lib/ace/search_highlight.js" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "constant", "@@" ], + [ "constant.numeric", " -0,0 +1,3 " ], + [ "constant", "@@" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.constant", "+" ], + [ "text", "new" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.constant", "+" ], + [ "text", "empty file" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_glsl.json b/lib/ace/mode/_test/tokens_glsl.json new file mode 100644 index 0000000000..5d5668dee4 --- /dev/null +++ b/lib/ace/mode/_test/tokens_glsl.json @@ -0,0 +1,185 @@ +[ + { + "state": "start", + "data": [ + [ "keyword", "uniform" ], + [ "text", " " ], + [ "keyword", "float" ], + [ "text", " " ], + [ "identifier", "amplitude" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "attribute" ], + [ "text", " " ], + [ "keyword", "float" ], + [ "text", " " ], + [ "identifier", "displacement" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "varying" ], + [ "text", " " ], + [ "keyword", "vec3" ], + [ "text", " " ], + [ "identifier", "vNormal" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "void" ], + [ "text", " " ], + [ "entity.name.function", "main" ], + [ "paren.lparen", "(" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "vNormal" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "identifier", "normal" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "comment", "// multiply our displacement by the" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "comment", "// amplitude. The amp will get animated" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "comment", "// so we'll have animated displacement" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "vec3" ], + [ "text", " " ], + [ "identifier", "newPosition" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "identifier", "position" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "text", " " ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "normal" ], + [ "text", " " ], + [ "keyword.operator", "*" ], + [ "text", " " ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "vec3" ], + [ "paren.lparen", "(" ], + [ "identifier", "displacement" ], + [ "text", " " ], + [ "keyword.operator", "*" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "amplitude" ], + [ "paren.rparen", ")" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "constant.language", "gl_Position" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "identifier", "projectionMatrix" ], + [ "text", " " ], + [ "keyword.operator", "*" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "modelViewMatrix" ], + [ "text", " " ], + [ "keyword.operator", "*" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "vec4" ], + [ "paren.lparen", "(" ], + [ "identifier", "newPosition" ], + [ "punctuation.operator", "," ], + [ "constant.numeric", "1.0" ], + [ "paren.rparen", ")" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_golang.json b/lib/ace/mode/_test/tokens_golang.json new file mode 100644 index 0000000000..edfb232aed --- /dev/null +++ b/lib/ace/mode/_test/tokens_golang.json @@ -0,0 +1,362 @@ +[ + { + "state": "start", + "data": [ + [ "comment", "// Concurrent computation of pi." ] + ] + }, + { + "state": "start", + "data": [ + [ "comment", "// See http://goo.gl/ZuTZM." ] + ] + }, + { + "state": "start", + "data": [ + [ "comment", "//" ] + ] + }, + { + "state": "start", + "data": [ + [ "comment", "// This demonstrates Go's ability to handle" ] + ] + }, + { + "state": "start", + "data": [ + [ "comment", "// large numbers of concurrent processes." ] + ] + }, + { + "state": "start", + "data": [ + [ "comment", "// It is an unreasonable way to calculate pi." ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "package" ], + [ "text", " " ], + [ "identifier", "main" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "import" ], + [ "text", " " ], + [ "paren.lparen", "(" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "string", "\"fmt\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "string", "\"math\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "func" ], + [ "text", " " ], + [ "identifier", "main" ], + [ "paren.lparen", "(" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "fmt" ], + [ "punctuation.operator", "." ], + [ "identifier", "Println" ], + [ "paren.lparen", "(" ], + [ "identifier", "pi" ], + [ "paren.lparen", "(" ], + [ "constant.numeric", "5000" ], + [ "paren.rparen", ")" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "comment", "// pi launches n goroutines to compute an" ] + ] + }, + { + "state": "start", + "data": [ + [ "comment", "// approximation of pi." ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "func" ], + [ "text", " " ], + [ "identifier", "pi" ], + [ "paren.lparen", "(" ], + [ "identifier", "n" ], + [ "text", " " ], + [ "identifier", "int" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "identifier", "float64" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "ch" ], + [ "text", " " ], + [ "punctuation.operator", ":" ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "identifier", "make" ], + [ "paren.lparen", "(" ], + [ "keyword", "chan" ], + [ "text", " " ], + [ "identifier", "float64" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "for" ], + [ "text", " " ], + [ "identifier", "k" ], + [ "text", " " ], + [ "punctuation.operator", ":" ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "constant.numeric", "0" ], + [ "punctuation.operator", ";" ], + [ "text", " " ], + [ "identifier", "k" ], + [ "text", " " ], + [ "keyword.operator", "<=" ], + [ "text", " " ], + [ "identifier", "n" ], + [ "punctuation.operator", ";" ], + [ "text", " " ], + [ "identifier", "k" ], + [ "keyword.operator", "++" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "go" ], + [ "text", " " ], + [ "identifier", "term" ], + [ "paren.lparen", "(" ], + [ "identifier", "ch" ], + [ "punctuation.operator", "," ], + [ "text", " " ], + [ "identifier", "float64" ], + [ "paren.lparen", "(" ], + [ "identifier", "k" ], + [ "paren.rparen", ")" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "f" ], + [ "text", " " ], + [ "punctuation.operator", ":" ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "constant.numeric", "0.0" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "for" ], + [ "text", " " ], + [ "identifier", "k" ], + [ "text", " " ], + [ "punctuation.operator", ":" ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "constant.numeric", "0" ], + [ "punctuation.operator", ";" ], + [ "text", " " ], + [ "identifier", "k" ], + [ "text", " " ], + [ "keyword.operator", "<=" ], + [ "text", " " ], + [ "identifier", "n" ], + [ "punctuation.operator", ";" ], + [ "text", " " ], + [ "identifier", "k" ], + [ "keyword.operator", "++" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "f" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "keyword.operator", "<" ], + [ "keyword.operator", "-" ], + [ "identifier", "ch" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "return" ], + [ "text", " " ], + [ "identifier", "f" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "func" ], + [ "text", " " ], + [ "identifier", "term" ], + [ "paren.lparen", "(" ], + [ "identifier", "ch" ], + [ "text", " " ], + [ "keyword", "chan" ], + [ "text", " " ], + [ "identifier", "float64" ], + [ "punctuation.operator", "," ], + [ "text", " " ], + [ "identifier", "k" ], + [ "text", " " ], + [ "identifier", "float64" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "ch" ], + [ "text", " " ], + [ "keyword.operator", "<" ], + [ "keyword.operator", "-" ], + [ "text", " " ], + [ "constant.numeric", "4" ], + [ "text", " " ], + [ "keyword.operator", "*" ], + [ "text", " " ], + [ "identifier", "math" ], + [ "punctuation.operator", "." ], + [ "identifier", "Pow" ], + [ "paren.lparen", "(" ], + [ "constant.numeric", "-1" ], + [ "punctuation.operator", "," ], + [ "text", " " ], + [ "identifier", "k" ], + [ "paren.rparen", ")" ], + [ "text", " / " ], + [ "paren.lparen", "(" ], + [ "constant.numeric", "2" ], + [ "keyword.operator", "*" ], + [ "identifier", "k" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "text", " " ], + [ "constant.numeric", "1" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_groovy.json b/lib/ace/mode/_test/tokens_groovy.json new file mode 100644 index 0000000000..2c73f16bb7 --- /dev/null +++ b/lib/ace/mode/_test/tokens_groovy.json @@ -0,0 +1,529 @@ +[ + { + "state": "start", + "data": [ + [ "comment", "//http://groovy.codehaus.org/Martin+Fowler%27s+closure+examples+in+Groovy" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "class" ], + [ "text", " " ], + [ "identifier", "Employee" ], + [ "text", " " ], + [ "lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "def" ], + [ "text", " " ], + [ "identifier", "name" ], + [ "text", ", " ], + [ "identifier", "salary" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "boolean" ], + [ "text", " " ], + [ "identifier", "manager" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "support.function", "String" ], + [ "text", " " ], + [ "identifier", "toString" ], + [ "lparen", "(" ], + [ "rparen", ")" ], + [ "text", " " ], + [ "lparen", "{" ], + [ "text", " " ], + [ "keyword", "return" ], + [ "text", " " ], + [ "identifier", "name" ], + [ "text", " " ], + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "def" ], + [ "text", " " ], + [ "identifier", "emps" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "lparen", "[" ], + [ "keyword", "new" ], + [ "text", " " ], + [ "identifier", "Employee" ], + [ "lparen", "(" ], + [ "identifier", "name" ], + [ "text", ":" ], + [ "string", "'Guillaume'" ], + [ "text", ", " ], + [ "identifier", "manager" ], + [ "text", ":" ], + [ "constant.language.boolean", "true" ], + [ "text", ", " ], + [ "identifier", "salary" ], + [ "text", ":" ], + [ "constant.numeric", "200" ], + [ "rparen", ")" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "new" ], + [ "text", " " ], + [ "identifier", "Employee" ], + [ "lparen", "(" ], + [ "identifier", "name" ], + [ "text", ":" ], + [ "string", "'Graeme'" ], + [ "text", ", " ], + [ "identifier", "manager" ], + [ "text", ":" ], + [ "constant.language.boolean", "true" ], + [ "text", ", " ], + [ "identifier", "salary" ], + [ "text", ":" ], + [ "constant.numeric", "200" ], + [ "rparen", ")" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "new" ], + [ "text", " " ], + [ "identifier", "Employee" ], + [ "lparen", "(" ], + [ "identifier", "name" ], + [ "text", ":" ], + [ "string", "'Dierk'" ], + [ "text", ", " ], + [ "identifier", "manager" ], + [ "text", ":" ], + [ "constant.language.boolean", "false" ], + [ "text", ", " ], + [ "identifier", "salary" ], + [ "text", ":" ], + [ "constant.numeric", "151" ], + [ "rparen", ")" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "new" ], + [ "text", " " ], + [ "identifier", "Employee" ], + [ "lparen", "(" ], + [ "identifier", "name" ], + [ "text", ":" ], + [ "string", "'Bernd'" ], + [ "text", ", " ], + [ "identifier", "manager" ], + [ "text", ":" ], + [ "constant.language.boolean", "false" ], + [ "text", ", " ], + [ "identifier", "salary" ], + [ "text", ":" ], + [ "constant.numeric", "50" ], + [ "rparen", ")" ], + [ "rparen", "]" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "def" ], + [ "text", " " ], + [ "identifier", "managers" ], + [ "lparen", "(" ], + [ "identifier", "emps" ], + [ "rparen", ")" ], + [ "text", " " ], + [ "lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "emps" ], + [ "text", "." ], + [ "identifier", "findAll" ], + [ "text", " " ], + [ "lparen", "{" ], + [ "text", " " ], + [ "identifier", "e" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "keyword.operator", ">" ], + [ "text", " " ], + [ "identifier", "e" ], + [ "text", "." ], + [ "identifier", "isManager" ], + [ "lparen", "(" ], + [ "rparen", ")" ], + [ "text", " " ], + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "assert" ], + [ "text", " " ], + [ "identifier", "emps" ], + [ "lparen", "[" ], + [ "constant.numeric", "0" ], + [ "text", ".." ], + [ "constant.numeric", "1" ], + [ "rparen", "]" ], + [ "text", " " ], + [ "keyword.operator", "==" ], + [ "text", " " ], + [ "identifier", "managers" ], + [ "lparen", "(" ], + [ "identifier", "emps" ], + [ "rparen", ")" ], + [ "text", " " ], + [ "comment", "// [Guillaume, Graeme]" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "def" ], + [ "text", " " ], + [ "identifier", "highPaid" ], + [ "lparen", "(" ], + [ "identifier", "emps" ], + [ "rparen", ")" ], + [ "text", " " ], + [ "lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "threshold" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "constant.numeric", "150" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "emps" ], + [ "text", "." ], + [ "identifier", "findAll" ], + [ "text", " " ], + [ "lparen", "{" ], + [ "text", " " ], + [ "identifier", "e" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "keyword.operator", ">" ], + [ "text", " " ], + [ "identifier", "e" ], + [ "text", "." ], + [ "identifier", "salary" ], + [ "text", " " ], + [ "keyword.operator", ">" ], + [ "text", " " ], + [ "identifier", "threshold" ], + [ "text", " " ], + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "assert" ], + [ "text", " " ], + [ "identifier", "emps" ], + [ "lparen", "[" ], + [ "constant.numeric", "0" ], + [ "text", ".." ], + [ "constant.numeric", "2" ], + [ "rparen", "]" ], + [ "text", " " ], + [ "keyword.operator", "==" ], + [ "text", " " ], + [ "identifier", "highPaid" ], + [ "lparen", "(" ], + [ "identifier", "emps" ], + [ "rparen", ")" ], + [ "text", " " ], + [ "comment", "// [Guillaume, Graeme, Dierk]" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "def" ], + [ "text", " " ], + [ "identifier", "paidMore" ], + [ "lparen", "(" ], + [ "identifier", "amount" ], + [ "rparen", ")" ], + [ "text", " " ], + [ "lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "lparen", "{" ], + [ "text", " " ], + [ "identifier", "e" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "keyword.operator", ">" ], + [ "text", " " ], + [ "identifier", "e" ], + [ "text", "." ], + [ "identifier", "salary" ], + [ "text", " " ], + [ "keyword.operator", ">" ], + [ "text", " " ], + [ "identifier", "amount" ], + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "def" ], + [ "text", " " ], + [ "identifier", "highPaid" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "identifier", "paidMore" ], + [ "lparen", "(" ], + [ "constant.numeric", "150" ], + [ "rparen", ")" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "assert" ], + [ "text", " " ], + [ "identifier", "highPaid" ], + [ "lparen", "(" ], + [ "identifier", "emps" ], + [ "lparen", "[" ], + [ "constant.numeric", "0" ], + [ "rparen", "]" ], + [ "rparen", ")" ], + [ "text", " " ], + [ "comment", "// true" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "assert" ], + [ "text", " " ], + [ "identifier", "emps" ], + [ "lparen", "[" ], + [ "constant.numeric", "0" ], + [ "text", ".." ], + [ "constant.numeric", "2" ], + [ "rparen", "]" ], + [ "text", " " ], + [ "keyword.operator", "==" ], + [ "text", " " ], + [ "identifier", "emps" ], + [ "text", "." ], + [ "identifier", "findAll" ], + [ "lparen", "(" ], + [ "identifier", "highPaid" ], + [ "rparen", ")" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "def" ], + [ "text", " " ], + [ "identifier", "filename" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "string", "'test.txt'" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "new" ], + [ "text", " " ], + [ "identifier", "File" ], + [ "lparen", "(" ], + [ "identifier", "filename" ], + [ "rparen", ")" ], + [ "text", "." ], + [ "identifier", "withReader" ], + [ "lparen", "{" ], + [ "text", " " ], + [ "identifier", "reader" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "keyword.operator", ">" ], + [ "text", " " ], + [ "identifier", "doSomethingWith" ], + [ "lparen", "(" ], + [ "identifier", "reader" ], + [ "rparen", ")" ], + [ "text", " " ], + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "def" ], + [ "text", " " ], + [ "identifier", "readersText" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "def" ], + [ "text", " " ], + [ "identifier", "doSomethingWith" ], + [ "lparen", "(" ], + [ "identifier", "reader" ], + [ "rparen", ")" ], + [ "text", " " ], + [ "lparen", "{" ], + [ "text", " " ], + [ "identifier", "readersText" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "identifier", "reader" ], + [ "text", "." ], + [ "identifier", "text" ], + [ "text", " " ], + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "assert" ], + [ "text", " " ], + [ "keyword", "new" ], + [ "text", " " ], + [ "identifier", "File" ], + [ "lparen", "(" ], + [ "identifier", "filename" ], + [ "rparen", ")" ], + [ "text", "." ], + [ "identifier", "text" ], + [ "text", " " ], + [ "keyword.operator", "==" ], + [ "text", " " ], + [ "identifier", "readersText" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_haxe.json b/lib/ace/mode/_test/tokens_haxe.json new file mode 100644 index 0000000000..bec79d5c04 --- /dev/null +++ b/lib/ace/mode/_test/tokens_haxe.json @@ -0,0 +1,195 @@ +[ + { + "state": "start", + "data": [ + [ "keyword", "class" ], + [ "text", " " ], + [ "identifier", "Haxe" ], + [ "text", " " ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "public" ], + [ "text", " " ], + [ "keyword", "static" ], + [ "text", " " ], + [ "keyword", "function" ], + [ "text", " " ], + [ "identifier", "main" ], + [ "paren.lparen", "(" ], + [ "paren.rparen", ")" ], + [ "text", " " ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "comment", "// Say Hello!" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "var" ], + [ "text", " " ], + [ "identifier", "greeting" ], + [ "punctuation.operator", ":" ], + [ "keyword", "String" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "string", "\"Hello World\"" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "trace" ], + [ "paren.lparen", "(" ], + [ "identifier", "greeting" ], + [ "paren.rparen", ")" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "var" ], + [ "text", " " ], + [ "identifier", "targets" ], + [ "punctuation.operator", ":" ], + [ "keyword", "Array" ], + [ "keyword.operator", "<" ], + [ "keyword", "String" ], + [ "keyword.operator", ">" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "paren.lparen", "[" ], + [ "string", "\"Flash\"" ], + [ "punctuation.operator", "," ], + [ "string", "\"Javascript\"" ], + [ "punctuation.operator", "," ], + [ "string", "\"PHP\"" ], + [ "punctuation.operator", "," ], + [ "string", "\"Neko\"" ], + [ "punctuation.operator", "," ], + [ "string", "\"C++\"" ], + [ "punctuation.operator", "," ], + [ "string", "\"iOS\"" ], + [ "punctuation.operator", "," ], + [ "string", "\"Android\"" ], + [ "punctuation.operator", "," ], + [ "string", "\"webOS\"" ], + [ "paren.rparen", "]" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "trace" ], + [ "paren.lparen", "(" ], + [ "string", "\"Haxe is a great language that can target:\"" ], + [ "paren.rparen", ")" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "for" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "identifier", "target" ], + [ "text", " " ], + [ "keyword", "in" ], + [ "text", " " ], + [ "identifier", "targets" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "trace" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "string", "\" - \"" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "text", " " ], + [ "identifier", "target" ], + [ "paren.rparen", ")" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "trace" ], + [ "paren.lparen", "(" ], + [ "string", "\"And many more!\"" ], + [ "paren.rparen", ")" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_html.json b/lib/ace/mode/_test/tokens_html.json new file mode 100644 index 0000000000..9b031aaff9 --- /dev/null +++ b/lib/ace/mode/_test/tokens_html.json @@ -0,0 +1,150 @@ +[ + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "html" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "head" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "css-start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name.style", "style" ], + [ "text", " " ], + [ "entity.other.attribute-name", "type" ], + [ "keyword.operator", "=" ], + [ "string", "\"text/css\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "css-ruleset", + "data": [ + [ "text", " " ], + [ "variable", ".text-layer" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "css-ruleset", + "data": [ + [ "text", " " ], + [ "support.type", "font-family" ], + [ "text", ": Monaco, " ], + [ "string", "\"Courier New\"" ], + [ "text", ", " ], + [ "support.constant.fonts", "monospace" ], + [ "text", ";" ] + ] + }, + { + "state": "css-ruleset", + "data": [ + [ "text", " " ], + [ "support.type", "font-size" ], + [ "text", ": " ], + [ "constant.numeric", "12" ], + [ "keyword", "px" ], + [ "text", ";" ] + ] + }, + { + "state": "css-ruleset", + "data": [ + [ "text", " " ], + [ "support.type", "cursor" ], + [ "text", ": " ], + [ "support.constant", "text" ], + [ "text", ";" ] + ] + }, + { + "state": "css-start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "body" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "h1" ], + [ "text", " " ], + [ "entity.other.attribute-name", "style" ], + [ "keyword.operator", "=" ], + [ "string", "\"color:red\"" ], + [ "meta.tag", ">" ], + [ "text", "Juhu Kinners" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_java.json b/lib/ace/mode/_test/tokens_java.json new file mode 100644 index 0000000000..376bdc7efe --- /dev/null +++ b/lib/ace/mode/_test/tokens_java.json @@ -0,0 +1,139 @@ +[ + { + "state": "start", + "data": [ + [ "keyword", "public" ], + [ "text", " " ], + [ "keyword", "class" ], + [ "text", " " ], + [ "identifier", "InfiniteLoop" ], + [ "text", " " ], + [ "lparen", "{" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "comment", + "data": [ + [ "text", " " ], + [ "comment", "/*" ] + ] + }, + { + "state": "comment", + "data": [ + [ "comment", " * This will cause the program to hang..." ] + ] + }, + { + "state": "comment", + "data": [ + [ "comment", " *" ] + ] + }, + { + "state": "comment", + "data": [ + [ "comment", " * Taken from:" ] + ] + }, + { + "state": "comment", + "data": [ + [ "comment", " * http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/" ] + ] + }, + { + "state": "start", + "data": [ + [ "comment", " */" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "public" ], + [ "text", " " ], + [ "keyword", "static" ], + [ "text", " " ], + [ "keyword", "void" ], + [ "text", " " ], + [ "identifier", "main" ], + [ "lparen", "(" ], + [ "support.function", "String" ], + [ "lparen", "[" ], + [ "rparen", "]" ], + [ "text", " " ], + [ "identifier", "args" ], + [ "rparen", ")" ], + [ "text", " " ], + [ "lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "double" ], + [ "text", " " ], + [ "identifier", "d" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "support.function", "Double" ], + [ "text", "." ], + [ "identifier", "parseDouble" ], + [ "lparen", "(" ], + [ "string", "\"2.2250738585072012e-308\"" ], + [ "rparen", ")" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "comment", "// unreachable code" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "support.function", "System" ], + [ "text", "." ], + [ "identifier", "out" ], + [ "text", "." ], + [ "identifier", "println" ], + [ "lparen", "(" ], + [ "string", "\"Value: \"" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "text", " " ], + [ "identifier", "d" ], + [ "rparen", ")" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "rparen", "}" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_javascript.json b/lib/ace/mode/_test/tokens_javascript.json new file mode 100644 index 0000000000..b27744c178 --- /dev/null +++ b/lib/ace/mode/_test/tokens_javascript.json @@ -0,0 +1,555 @@ +[ + { + "state": "regex_allowed", + "data": [ + [ "storage.type", "function" ], + [ "text", " " ], + [ "entity.name.function", "foo" ], + [ "paren.lparen", "(" ], + [ "variable.parameter", "items" ], + [ "punctuation.operator", ", " ], + [ "variable.parameter", "nada" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "regex_allowed", + "data": [ + [ "text", " " ], + [ "keyword", "for" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "storage.type", "var" ], + [ "text", " " ], + [ "identifier", "i" ], + [ "keyword.operator", "=" ], + [ "constant.numeric", "0" ], + [ "punctuation.operator", ";" ], + [ "text", " " ], + [ "identifier", "i" ], + [ "keyword.operator", "<" ], + [ "identifier", "items" ], + [ "punctuation.operator", "." ], + [ "support.constant", "length" ], + [ "punctuation.operator", ";" ], + [ "text", " " ], + [ "identifier", "i" ], + [ "keyword.operator", "++" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "regex_allowed", + "data": [ + [ "text", " " ], + [ "identifier", "alert" ], + [ "paren.lparen", "(" ], + [ "identifier", "items" ], + [ "paren.lparen", "[" ], + [ "identifier", "i" ], + [ "paren.rparen", "]" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "text", " " ], + [ "string", "\"juhu" ], + [ "constant.language.escape", "\\n" ], + [ "string", "\"" ], + [ "paren.rparen", ")" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ], + [ "text", "\t" ], + [ "comment", "// Real Tab." ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "identifier", "regexp" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "string.regexp", "/p" ], + [ "constant.language.escape", "|" ], + [ "string.regexp", "p/" ], + [ "text", " " ], + [ "comment", "// ends here" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "identifier", "r" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "string.regexp", "/d" ], + [ "constant.language.escape", "{1,2}" ], + [ "constant.language.escape", "?" ], + [ "string.regexp", "f{e}" ], + [ "invalid", "++" ], + [ "string.regexp", "r" ], + [ "constant.language.escape", "*?" ], + [ "regexp.keyword.operator", "\\d" ], + [ "constant.language.escape", "+?[]" ], + [ "string.regexp", "r" ], + [ "constant.language.escape", "[^" ], + [ "string.regexp.charachterclass", "r" ], + [ "constant.language.escape", "-" ], + [ "string.regexp.charachterclass", "o" ], + [ "regexp.keyword.operator", "\\f" ], + [ "regexp.keyword.operator", "\\f" ], + [ "string.regexp.charachterclass", "[" ], + [ "regexp.keyword.operator", "\\f" ], + [ "constant.language.escape", "]" ], + [ "constant.language.escape", "?" ], + [ "string.regexp", "r" ], + [ "invalid", "{7}+" ], + [ "string.regexp", "r" ], + [ "regexp.keyword.operator", "\\{" ], + [ "string.regexp", "7}" ], + [ "constant.language.escape", "+" ], + [ "string.regexp", "rr--rr" ], + [ "constant.language.escape", "$" ], + [ "constant.language.escape", "^" ], + [ "constant.language.escape", "(?:" ], + [ "string.regexp", "d" ], + [ "constant.language.escape", "|" ], + [ "string.regexp", "s" ], + [ "constant.language.escape", ")" ], + [ "constant.language.escape", "(?=" ], + [ "string.regexp", "a" ], + [ "constant.language.escape", "|" ], + [ "constant.language.escape", ")" ], + [ "constant.language.escape", "(?!" ], + [ "string.regexp", "y" ], + [ "constant.language.escape", ")[]" ], + [ "constant.language.escape", "|" ], + [ "constant.language.escape", "$" ], + [ "constant.language.escape", "?" ], + [ "constant.language.escape", "|" ], + [ "invalid", "^*" ], + [ "string.regexp", "/" ], + [ "text", " " ], + [ "identifier", "o" ] + ] + }, + { + "state": "start", + "data": [ + [ "identifier", "a" ], + [ "keyword.operator", "=" ], + [ "string.regexp", "/a/" ], + [ "text", " " ], + [ "identifier", "jk" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "string.regexp", "/ /" ], + [ "text", " " ], + [ "keyword.operator", "/" ], + [ "text", " " ], + [ "string.regexp", "/ /" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "comment.doc", "/************************************/" ] + ] + }, + { + "state": "start", + "data": [ + [ "comment.doc", "/** total mess, tricky to highlight**/" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "regex_allowed", + "data": [ + [ "storage.type", "function" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "doc-start", + "data": [ + [ "text", "\t" ], + [ "comment.doc", "/**" ] + ] + }, + { + "state": "doc-start", + "data": [ + [ "comment.doc", "\t * docComment" ] + ] + }, + { + "state": "start", + "data": [ + [ "comment.doc", "\t **/" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "identifier", "r" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "string.regexp", "/u" ], + [ "regexp.keyword.operator", "\\t" ], + [ "constant.language.escape", "*" ], + [ "string.regexp", "/" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "identifier", "g" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "constant.numeric", "1." ], + [ "text", "00" ], + [ "identifier", "E" ], + [ "text", "^" ], + [ "constant.numeric", "1" ], + [ "punctuation.operator", "," ], + [ "text", " " ], + [ "identifier", "y" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "constant.numeric", "1.2" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "text", " " ], + [ "punctuation.operator", "." ], + [ "constant.numeric", "2" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "text", " " ], + [ "constant.numeric", "052" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "text", " " ], + [ "constant.numeric", "0x25" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "identifier", "t" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "paren.lparen", "[" ], + [ "string", "'d'" ], + [ "punctuation.operator", "," ], + [ "text", " " ], + [ "string", "''" ], + [ "paren.rparen", "]" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + }, + { + "state": "regex_allowed", + "data": [ + [ "storage.type", "function" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "regex_allowed", + "data": [ + [ "text", "\t" ], + [ "comment", "/* eee */" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "qqstring", + "data": [ + [ "string", "\"s\\" ] + ] + }, + { + "state": "start", + "data": [ + [ "string", "s" ], + [ "constant.language.escape", "\\u7824" ], + [ "string", "sss" ], + [ "constant.language.escape", "\\u" ], + [ "string", "1\"" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "qstring", + "data": [ + [ "string", "'\\" ] + ] + }, + { + "state": "start", + "data": [ + [ "string", "string'" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "'" ] + ] + }, + { + "state": "start", + "data": [ + [ "identifier", "string" ], + [ "text", "'" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "string", "\"trailing space" ], + [ "constant.language.escape", "\\ " ], + [ "string", " " ] + ] + }, + { + "state": "start", + "data": [ + [ "string", "\" \"" ], + [ "text", " " ], + [ "keyword.operator", "/" ], + [ "identifier", "not" ], + [ "text", " " ], + [ "identifier", "a" ], + [ "text", " " ], + [ "identifier", "regexp" ], + [ "keyword.operator", "/" ], + [ "identifier", "g" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "doc-start", + "data": [ + [ "comment.doc", "/**" ] + ] + }, + { + "state": "doc-start", + "data": [ + [ "comment.doc", " *doc" ] + ] + }, + { + "state": "start", + "data": [ + [ "comment.doc", " */" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "regex_allowed", + "data": [ + [ "identifier", "a" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "regex_allowed", + "data": [ + [ "text", "\t" ], + [ "string", "'a'" ], + [ "punctuation.operator", ":" ], + [ "text", " " ], + [ "identifier", "b" ], + [ "punctuation.operator", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "string", "'g'" ], + [ "text", ": " ], + [ "storage.type", "function" ], + [ "paren.lparen", "(" ], + [ "variable.parameter", "t" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "entity.name.function", "gta" ], + [ "punctuation.operator", ":" ], + [ "storage.type", "function" ], + [ "paren.lparen", "(" ], + [ "variable.parameter", "a" ], + [ "punctuation.operator", "," ], + [ "variable.parameter", "b" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "function_arguments", + "data": [ + [ "identifier", "foo" ], + [ "punctuation.operator", "." ], + [ "storage.type", "protoype" ], + [ "punctuation.operator", "." ], + [ "entity.name.function", "d" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "storage.type", "function" ], + [ "paren.lparen", "(" ], + [ "variable.parameter", "a" ], + [ "punctuation.operator", ", " ], + [ "variable.parameter", "b" ], + [ "punctuation.operator", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "punctuation.operator", " " ], + [ "variable.parameter", "c" ], + [ "punctuation.operator", ", " ], + [ "variable.parameter", "d" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "storage.type", "foo" ], + [ "punctuation.operator", "." ], + [ "entity.name.function", "d" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "storage.type", "function" ], + [ "paren.lparen", "(" ], + [ "variable.parameter", "a" ], + [ "punctuation.operator", ", " ], + [ "variable.parameter", "b" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "storage.type", "foo" ], + [ "punctuation.operator", "." ], + [ "entity.name.function", "d" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "storage.type", "function" ], + [ "paren.lparen", "(" ], + [ "variable.parameter", "a" ], + [ "punctuation.operator", ", " ], + [ "comment.doc", "/*****/" ], + [ "text", " " ], + [ "identifier", "d" ], + [ "string", "\"string\"" ], + [ "text", " " ] + ] + }, + { + "state": "start", + "data": [] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_json.json b/lib/ace/mode/_test/tokens_json.json new file mode 100644 index 0000000000..22dc2db763 --- /dev/null +++ b/lib/ace/mode/_test/tokens_json.json @@ -0,0 +1,611 @@ +[ + { + "state": "start", + "data": [ + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"query\"" ], + [ "text", ": " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"count\"" ], + [ "text", ": " ], + [ "constant.numeric", "10" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"created\"" ], + [ "text", ": " ], + [ "string", "\"2011-06-21T08:10:46Z\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"lang\"" ], + [ "text", ": " ], + [ "string", "\"en-US\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"results\"" ], + [ "text", ": " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"photo\"" ], + [ "text", ": " ], + [ "paren.lparen", "[" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"farm\"" ], + [ "text", ": " ], + [ "string", "\"6\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"id\"" ], + [ "text", ": " ], + [ "string", "\"5855620975\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"isfamily\"" ], + [ "text", ": " ], + [ "string", "\"0\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"isfriend\"" ], + [ "text", ": " ], + [ "string", "\"0\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"ispublic\"" ], + [ "text", ": " ], + [ "string", "\"1\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"owner\"" ], + [ "text", ": " ], + [ "string", "\"32021554@N04\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"secret\"" ], + [ "text", ": " ], + [ "string", "\"f1f5e8515d\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"server\"" ], + [ "text", ": " ], + [ "string", "\"5110\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"title\"" ], + [ "text", ": " ], + [ "string", "\"7087 bandit cat\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"farm\"" ], + [ "text", ": " ], + [ "string", "\"4\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"id\"" ], + [ "text", ": " ], + [ "string", "\"5856170534\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"isfamily\"" ], + [ "text", ": " ], + [ "string", "\"0\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"isfriend\"" ], + [ "text", ": " ], + [ "string", "\"0\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"ispublic\"" ], + [ "text", ": " ], + [ "string", "\"1\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"owner\"" ], + [ "text", ": " ], + [ "string", "\"32021554@N04\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"secret\"" ], + [ "text", ": " ], + [ "string", "\"ff1efb2a6f\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"server\"" ], + [ "text", ": " ], + [ "string", "\"3217\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"title\"" ], + [ "text", ": " ], + [ "string", "\"6975 rusty cat\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"farm\"" ], + [ "text", ": " ], + [ "string", "\"6\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"id\"" ], + [ "text", ": " ], + [ "string", "\"5856172972\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"isfamily\"" ], + [ "text", ": " ], + [ "string", "\"0\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"isfriend\"" ], + [ "text", ": " ], + [ "string", "\"0\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"ispublic\"" ], + [ "text", ": " ], + [ "string", "\"1\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"owner\"" ], + [ "text", ": " ], + [ "string", "\"51249875@N03\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"secret\"" ], + [ "text", ": " ], + [ "string", "\"6c6887347c\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"server\"" ], + [ "text", ": " ], + [ "string", "\"5192\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"title\"" ], + [ "text", ": " ], + [ "string", "\"watermarked-cats\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"farm\"" ], + [ "text", ": " ], + [ "string", "\"6\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"id\"" ], + [ "text", ": " ], + [ "string", "\"5856168328\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"isfamily\"" ], + [ "text", ": " ], + [ "string", "\"0\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"isfriend\"" ], + [ "text", ": " ], + [ "string", "\"0\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"ispublic\"" ], + [ "text", ": " ], + [ "string", "\"1\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"owner\"" ], + [ "text", ": " ], + [ "string", "\"32021554@N04\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"secret\"" ], + [ "text", ": " ], + [ "string", "\"0c1cfdf64c\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"server\"" ], + [ "text", ": " ], + [ "string", "\"5078\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"title\"" ], + [ "text", ": " ], + [ "string", "\"7020 mandy cat\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"farm\"" ], + [ "text", ": " ], + [ "string", "\"3\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"id\"" ], + [ "text", ": " ], + [ "string", "\"5856171774\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"isfamily\"" ], + [ "text", ": " ], + [ "string", "\"0\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"isfriend\"" ], + [ "text", ": " ], + [ "string", "\"0\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"ispublic\"" ], + [ "text", ": " ], + [ "string", "\"1\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"owner\"" ], + [ "text", ": " ], + [ "string", "\"32021554@N04\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"secret\"" ], + [ "text", ": " ], + [ "string", "\"7f5a3180ab\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"server\"" ], + [ "text", ": " ], + [ "string", "\"2696\"" ], + [ "text", "," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "\"title\"" ], + [ "text", ": " ], + [ "string", "\"7448 bobby cat\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "]" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_jsx.json b/lib/ace/mode/_test/tokens_jsx.json new file mode 100644 index 0000000000..d7a227c9a7 --- /dev/null +++ b/lib/ace/mode/_test/tokens_jsx.json @@ -0,0 +1,79 @@ +[ + { + "state": "comment", + "data": [ + [ "comment", "/*EXPECTED" ] + ] + }, + { + "state": "comment", + "data": [ + [ "comment", "hello world!" ] + ] + }, + { + "state": "start", + "data": [ + [ "comment", "*/" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "class" ], + [ "text", " " ], + [ "language.support.class", "Test" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "static" ], + [ "text", " " ], + [ "storage.type", "function" ], + [ "text", " " ], + [ "entity.name.function", "run" ], + [ "paren.lparen", "(" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "punctuation.operator", ":" ], + [ "text", " " ], + [ "keyword", "void" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "comment", "// console.log(\"hello world!\");" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "log" ], + [ "text", " " ], + [ "string", "\"hello world!\"" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_latex.json b/lib/ace/mode/_test/tokens_latex.json new file mode 100644 index 0000000000..0abe75eda2 --- /dev/null +++ b/lib/ace/mode/_test/tokens_latex.json @@ -0,0 +1,196 @@ +[ + { + "state": "start", + "data": [ + [ "keyword", "\\usepackage" ], + [ "lparen", "{" ], + [ "text", "amsmath" ], + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "\\title" ], + [ "lparen", "{" ], + [ "keyword", "\\LaTeX" ], + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "\\date" ], + [ "lparen", "{" ], + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "\\begin" ], + [ "lparen", "{" ], + [ "text", "document" ], + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "\\maketitle" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "\\LaTeX" ], + [ "lparen", "{" ], + [ "rparen", "}" ], + [ "text", " is a document preparation system for the " ], + [ "keyword", "\\TeX" ], + [ "lparen", "{" ], + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " typesetting program. It offers programmable desktop publishing" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " features and extensive facilities for automating most aspects of" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " typesetting and desktop publishing, including numbering and" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " cross-referencing, tables and figures, page layout, bibliographies," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " and much more. " ], + [ "keyword", "\\LaTeX" ], + [ "lparen", "{" ], + [ "rparen", "}" ], + [ "text", " was originally written in 1984 by Leslie" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " Lamport and has become the dominant method for using " ], + [ "keyword", "\\TeX" ], + [ "text", "; few" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " people write in plain " ], + [ "keyword", "\\TeX" ], + [ "lparen", "{" ], + [ "rparen", "}" ], + [ "text", " anymore. The current version is" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "\\LaTeXe" ], + [ "text", "." ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "comment", "% This is a comment; it will not be shown in the final output." ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "comment", "% The following shows a little of the typesetting power of LaTeX:" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "\\begin" ], + [ "lparen", "{" ], + [ "text", "align" ], + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " E &= mc^2 " ], + [ "keyword", "\\\\" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " m &= " ], + [ "keyword", "\\frac" ], + [ "lparen", "{" ], + [ "text", "m_0" ], + [ "rparen", "}" ], + [ "lparen", "{" ], + [ "keyword", "\\sqrt" ], + [ "lparen", "{" ], + [ "text", "1-" ], + [ "keyword", "\\frac" ], + [ "lparen", "{" ], + [ "text", "v^2" ], + [ "rparen", "}" ], + [ "lparen", "{" ], + [ "text", "c^2" ], + [ "rparen", "}" ], + [ "rparen", "}" ], + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "\\end" ], + [ "lparen", "{" ], + [ "text", "align" ], + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "\\end" ], + [ "lparen", "{" ], + [ "text", "document" ], + [ "rparen", "}" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_less.json b/lib/ace/mode/_test/tokens_less.json new file mode 100644 index 0000000000..5a9f91b664 --- /dev/null +++ b/lib/ace/mode/_test/tokens_less.json @@ -0,0 +1,292 @@ +[ + { + "state": "start", + "data": [ + [ "comment", "/*" ], + [ "comment", " styles.less */" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "variable", "@base" ], + [ "text", ": " ], + [ "constant.numeric", "#f938ab" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "variable.language", ".box-shadow" ], + [ "paren.lparen", "(" ], + [ "variable", "@style" ], + [ "text", ", " ], + [ "variable", "@c" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "keyword", "when" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "support.function", "iscolor" ], + [ "paren.lparen", "(" ], + [ "variable", "@c" ], + [ "paren.rparen", ")" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " box-shadow: " ], + [ "variable", "@style" ], + [ "text", " " ], + [ "variable", "@c" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " -webkit-box-shadow: " ], + [ "variable", "@style" ], + [ "text", " " ], + [ "variable", "@c" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " -moz-box-shadow: " ], + [ "variable", "@style" ], + [ "text", " " ], + [ "variable", "@c" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "variable.language", ".box-shadow" ], + [ "paren.lparen", "(" ], + [ "variable", "@style" ], + [ "text", ", " ], + [ "variable", "@alpha" ], + [ "text", ": " ], + [ "constant.numeric", "50%" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "keyword", "when" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "support.function", "isnumber" ], + [ "paren.lparen", "(" ], + [ "variable", "@alpha" ], + [ "paren.rparen", ")" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable.language", ".box-shadow" ], + [ "paren.lparen", "(" ], + [ "variable", "@style" ], + [ "text", ", " ], + [ "support.function", "rgba" ], + [ "paren.lparen", "(" ], + [ "constant.numeric", "0" ], + [ "text", ", " ], + [ "constant.numeric", "0" ], + [ "text", ", " ], + [ "constant.numeric", "0" ], + [ "text", ", " ], + [ "variable", "@alpha" ], + [ "paren.rparen", ")" ], + [ "paren.rparen", ")" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "comment", "// Box styles" ] + ] + }, + { + "state": "start", + "data": [ + [ "variable.language", ".box" ], + [ "text", " " ], + [ "paren.lparen", "{" ], + [ "text", " " ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "support.type", "color" ], + [ "text", ": " ], + [ "support.function", "saturate" ], + [ "paren.lparen", "(" ], + [ "variable", "@base" ], + [ "text", ", " ], + [ "constant.numeric", "5%" ], + [ "paren.rparen", ")" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "support.type", "border-color" ], + [ "text", ": " ], + [ "support.function", "lighten" ], + [ "paren.lparen", "(" ], + [ "variable", "@base" ], + [ "text", ", " ], + [ "constant.numeric", "30%" ], + [ "paren.rparen", ")" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable.language", "div" ], + [ "text", " " ], + [ "paren.lparen", "{" ], + [ "text", " " ], + [ "variable.language", ".box-shadow" ], + [ "paren.lparen", "(" ], + [ "constant.numeric", "0" ], + [ "text", " " ], + [ "constant.numeric", "0" ], + [ "text", " " ], + [ "constant.numeric", "5px" ], + [ "text", ", " ], + [ "constant.numeric", "30%" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable.language", "a" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "support.type", "color" ], + [ "text", ": " ], + [ "variable", "@base" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " &" ], + [ "variable.language", ":hover" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "support.type", "color" ], + [ "text", ": " ], + [ "support.function", "lighten" ], + [ "paren.lparen", "(" ], + [ "variable", "@base" ], + [ "text", ", " ], + [ "constant.numeric", "50%" ], + [ "paren.rparen", ")" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_liquid.json b/lib/ace/mode/_test/tokens_liquid.json new file mode 100644 index 0000000000..73c37daaef --- /dev/null +++ b/lib/ace/mode/_test/tokens_liquid.json @@ -0,0 +1,698 @@ +[ + { + "state": "start", + "data": [ + [ "text", "The following examples can be found in full at http://liquidmarkup.org/" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Liquid is an extraction from the e-commerce system Shopify." ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "Shopify powers many thousands of e-commerce stores which all call for unique designs." ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "For this we developed Liquid which allows our customers complete design freedom while" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "maintaining the integrity of our servers." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Liquid has been in production use since June 2006 and is now used by many other" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "hosted web applications." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "It was developed for usage in Ruby on Rails web applications and integrates seamlessly" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "as a plugin but it also works excellently as a stand alone library." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Here's what it looks like:" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "ul" ], + [ "text", " " ], + [ "entity.other.attribute-name", "id" ], + [ "keyword.operator", "=" ], + [ "string", "\"products\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "{%" ], + [ "text", " " ], + [ "keyword", "for" ], + [ "text", " " ], + [ "identifier", "product" ], + [ "text", " " ], + [ "keyword", "in" ], + [ "text", " " ], + [ "identifier", "products" ], + [ "text", " " ], + [ "variable", "%}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "li" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "h2" ], + [ "meta.tag", ">" ], + [ "variable", "{{" ], + [ "text", " " ], + [ "identifier", "product" ], + [ "text", "." ], + [ "identifier", "title" ], + [ "text", " " ], + [ "variable", "}}" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " Only {{ product.price | format_as_money }}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "p" ], + [ "meta.tag", ">" ], + [ "variable", "{{" ], + [ "text", " " ], + [ "identifier", "product" ], + [ "text", "." ], + [ "identifier", "description" ], + [ "text", " | " ], + [ "identifier", "prettyprint" ], + [ "text", " | " ], + [ "support.function", "truncate" ], + [ "text", ": " ], + [ "constant.numeric", "200" ], + [ "text", " " ], + [ "variable", "}}" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "{%" ], + [ "text", " " ], + [ "keyword", "endfor" ], + [ "text", " " ], + [ "variable", "%}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Some more features include:" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "h2" ], + [ "meta.tag", ">" ], + [ "text", "Filters" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "p" ], + [ "meta.tag", ">" ], + [ "text", " The word \"tobi\" in uppercase: {{ 'tobi' | upcase }} " ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "p" ], + [ "meta.tag", ">" ], + [ "text", "The word \"tobi\" has {{ 'tobi' | size }} letters! " ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "p" ], + [ "meta.tag", ">" ], + [ "text", "Change \"Hello world\" to \"Hi world\": {{ 'Hello world' | replace: 'Hello', 'Hi' }} " ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "p" ], + [ "meta.tag", ">" ], + [ "text", "The date today is {{ 'now' | date: \"%Y %b %d\" }} " ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "h2" ], + [ "meta.tag", ">" ], + [ "text", "If" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "p" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "{%" ], + [ "text", " " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "identifier", "user" ], + [ "text", "." ], + [ "identifier", "name" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "string", "'tobi'" ], + [ "text", " " ], + [ "identifier", "or" ], + [ "text", " " ], + [ "identifier", "user" ], + [ "text", "." ], + [ "identifier", "name" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "string", "'marc'" ], + [ "text", " " ], + [ "variable", "%}" ], + [ "text", " " ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " hi marc or tobi" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "{%" ], + [ "text", " " ], + [ "keyword", "endif" ], + [ "text", " " ], + [ "variable", "%}" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "h2" ], + [ "meta.tag", ">" ], + [ "text", "Case" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "p" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "{%" ], + [ "text", " " ], + [ "keyword", "case" ], + [ "text", " " ], + [ "identifier", "template" ], + [ "text", " " ], + [ "variable", "%}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "{%" ], + [ "text", " " ], + [ "keyword", "when" ], + [ "text", " " ], + [ "string", "'index'" ], + [ "text", " " ], + [ "variable", "%}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " Welcome" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "{%" ], + [ "text", " " ], + [ "keyword", "when" ], + [ "text", " " ], + [ "string", "'product'" ], + [ "text", " " ], + [ "variable", "%}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "{{" ], + [ "text", " " ], + [ "identifier", "product" ], + [ "text", "." ], + [ "identifier", "vendor" ], + [ "text", " | " ], + [ "identifier", "link_to_vendor" ], + [ "text", " " ], + [ "variable", "}}" ], + [ "text", " / {{ product.title }}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "{%" ], + [ "text", " " ], + [ "keyword", "else" ], + [ "text", " " ], + [ "variable", "%}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "{{" ], + [ "text", " " ], + [ "identifier", "page_title" ], + [ "text", " " ], + [ "variable", "}}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "{%" ], + [ "text", " " ], + [ "keyword", "endcase" ], + [ "text", " " ], + [ "variable", "%}" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "h2" ], + [ "meta.tag", ">" ], + [ "text", "For Loops" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "p" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "{%" ], + [ "text", " " ], + [ "keyword", "for" ], + [ "text", " " ], + [ "identifier", "item" ], + [ "text", " " ], + [ "keyword", "in" ], + [ "text", " " ], + [ "identifier", "array" ], + [ "text", " " ], + [ "variable", "%}" ], + [ "text", " " ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "{{" ], + [ "text", " " ], + [ "identifier", "item" ], + [ "text", " " ], + [ "variable", "}}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "{%" ], + [ "text", " " ], + [ "keyword", "endfor" ], + [ "text", " " ], + [ "variable", "%}" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "h2" ], + [ "meta.tag", ">" ], + [ "text", "Tables" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "p" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "{%" ], + [ "text", " " ], + [ "keyword", "tablerow" ], + [ "text", " " ], + [ "identifier", "item" ], + [ "text", " " ], + [ "keyword", "in" ], + [ "text", " " ], + [ "identifier", "items" ], + [ "text", " " ], + [ "identifier", "cols" ], + [ "text", ": " ], + [ "constant.numeric", "3" ], + [ "text", " " ], + [ "variable", "%}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "{%" ], + [ "text", " " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "variable.language", "tablerowloop" ], + [ "text", "." ], + [ "identifier", "col_first" ], + [ "text", " " ], + [ "variable", "%}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " First column: {{ item.variable }}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "{%" ], + [ "text", " " ], + [ "keyword", "else" ], + [ "text", " " ], + [ "variable", "%}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " Different column: {{ item.variable }}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "{%" ], + [ "text", " " ], + [ "keyword", "endif" ], + [ "text", " " ], + [ "variable", "%}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "{%" ], + [ "text", " " ], + [ "keyword", "endtablerow" ], + [ "text", " " ], + [ "variable", "%}" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_lua.json b/lib/ace/mode/_test/tokens_lua.json new file mode 100644 index 0000000000..f249f6587c --- /dev/null +++ b/lib/ace/mode/_test/tokens_lua.json @@ -0,0 +1,451 @@ +[ + { + "state": "qcomment", + "data": [ + [ "comment", "--[[--" ] + ] + }, + { + "state": "qcomment", + "data": [ + [ "comment", "num_args takes in 5.1 byte code and extracts the number of arguments" ] + ] + }, + { + "state": "qcomment", + "data": [ + [ "comment", "from its function header." ] + ] + }, + { + "state": "start", + "data": [ + [ "comment", "--]]" ], + [ "comment", "--" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "function" ], + [ "text", " " ], + [ "identifier", "int" ], + [ "paren.lparen", "(" ], + [ "identifier", "t" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "keyword", "return" ], + [ "text", " " ], + [ "identifier", "t" ], + [ "keyword.operator", ":" ], + [ "support.function", "byte" ], + [ "paren.lparen", "(" ], + [ "constant.numeric", "1" ], + [ "paren.rparen", ")" ], + [ "keyword.operator", "+" ], + [ "identifier", "t" ], + [ "keyword.operator", ":" ], + [ "support.function", "byte" ], + [ "paren.lparen", "(" ], + [ "constant.numeric", "2" ], + [ "paren.rparen", ")" ], + [ "keyword.operator", "*" ], + [ "constant.numeric", "0x100" ], + [ "keyword.operator", "+" ], + [ "identifier", "t" ], + [ "keyword.operator", ":" ], + [ "support.function", "byte" ], + [ "paren.lparen", "(" ], + [ "constant.numeric", "3" ], + [ "paren.rparen", ")" ], + [ "keyword.operator", "*" ], + [ "constant.numeric", "0x10000" ], + [ "keyword.operator", "+" ], + [ "identifier", "t" ], + [ "keyword.operator", ":" ], + [ "support.function", "byte" ], + [ "paren.lparen", "(" ], + [ "constant.numeric", "4" ], + [ "paren.rparen", ")" ], + [ "keyword.operator", "*" ], + [ "constant.numeric", "0x1000000" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "end" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "function" ], + [ "text", " " ], + [ "identifier", "num_args" ], + [ "paren.lparen", "(" ], + [ "identifier", "func" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "keyword", "local" ], + [ "text", " " ], + [ "support.function", "dump" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "constant.library", "string" ], + [ "text", "." ], + [ "support.function", "dump" ], + [ "paren.lparen", "(" ], + [ "identifier", "func" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "keyword", "local" ], + [ "text", " " ], + [ "identifier", "offset" ], + [ "text", ", " ], + [ "identifier", "cursor" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "identifier", "int" ], + [ "paren.lparen", "(" ], + [ "support.function", "dump" ], + [ "keyword.operator", ":" ], + [ "support.function", "sub" ], + [ "paren.lparen", "(" ], + [ "constant.numeric", "13" ], + [ "paren.rparen", ")" ], + [ "paren.rparen", ")" ], + [ "text", ", " ], + [ "identifier", "offset" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "text", " " ], + [ "constant.numeric", "26" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "comment", "--Get the params and var flag (whether there's a ... in the param)" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "keyword", "return" ], + [ "text", " " ], + [ "support.function", "dump" ], + [ "keyword.operator", ":" ], + [ "support.function", "sub" ], + [ "paren.lparen", "(" ], + [ "identifier", "cursor" ], + [ "paren.rparen", ")" ], + [ "keyword.operator", ":" ], + [ "support.function", "byte" ], + [ "paren.lparen", "(" ], + [ "paren.rparen", ")" ], + [ "text", ", " ], + [ "support.function", "dump" ], + [ "keyword.operator", ":" ], + [ "support.function", "sub" ], + [ "paren.lparen", "(" ], + [ "identifier", "cursor" ], + [ "keyword.operator", "+" ], + [ "constant.numeric", "1" ], + [ "paren.rparen", ")" ], + [ "keyword.operator", ":" ], + [ "support.function", "byte" ], + [ "paren.lparen", "(" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "end" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "comment", "-- Usage:" ] + ] + }, + { + "state": "start", + "data": [ + [ "identifier", "num_args" ], + [ "paren.lparen", "(" ], + [ "keyword", "function" ], + [ "paren.lparen", "(" ], + [ "identifier", "a" ], + [ "text", "," ], + [ "identifier", "b" ], + [ "text", "," ], + [ "identifier", "c" ], + [ "text", "," ], + [ "identifier", "d" ], + [ "text", ", " ], + [ "keyword.operator", "..." ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "keyword", "end" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "comment", "-- return 4, 7" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "comment", "-- Python styled string format operator" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "local" ], + [ "text", " " ], + [ "identifier", "gm" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "constant.library", "debug" ], + [ "text", "." ], + [ "support.function", "getmetatable" ], + [ "paren.lparen", "(" ], + [ "string", "\"\"" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "identifier", "gm" ], + [ "text", "." ], + [ "support.function", "__mod" ], + [ "keyword.operator", "=" ], + [ "keyword", "function" ], + [ "paren.lparen", "(" ], + [ "identifier", "self" ], + [ "text", ", " ], + [ "identifier", "other" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "support.function", "type" ], + [ "paren.lparen", "(" ], + [ "identifier", "other" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "keyword.operator", "~" ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "string", "\"table\"" ], + [ "text", " " ], + [ "keyword", "then" ], + [ "text", " " ], + [ "identifier", "other" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "paren.lparen", "{" ], + [ "identifier", "other" ], + [ "paren.rparen", "}" ], + [ "text", " " ], + [ "keyword", "end" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "for" ], + [ "text", " " ], + [ "identifier", "i" ], + [ "text", "," ], + [ "identifier", "v" ], + [ "text", " " ], + [ "keyword", "in" ], + [ "text", " " ], + [ "support.function", "ipairs" ], + [ "paren.lparen", "(" ], + [ "identifier", "other" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "keyword", "do" ], + [ "text", " " ], + [ "identifier", "other" ], + [ "paren.lparen", "[" ], + [ "identifier", "i" ], + [ "paren.rparen", "]" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "support.function", "tostring" ], + [ "paren.lparen", "(" ], + [ "identifier", "v" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "keyword", "end" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "return" ], + [ "text", " " ], + [ "identifier", "self" ], + [ "keyword.operator", ":" ], + [ "support.function", "format" ], + [ "paren.lparen", "(" ], + [ "support.function", "unpack" ], + [ "paren.lparen", "(" ], + [ "identifier", "other" ], + [ "paren.rparen", ")" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "end" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "qstring3", + "data": [ + [ "support.function", "print" ], + [ "paren.lparen", "(" ], + [ "string", "[===[" ] + ] + }, + { + "state": "qstring3", + "data": [ + [ "string", " blah blah %s, (%d %d)" ] + ] + }, + { + "state": "start", + "data": [ + [ "string", "]===]" ], + [ "keyword.operator", "%" ], + [ "paren.lparen", "{" ], + [ "string", "\"blah\"" ], + [ "text", ", " ], + [ "identifier", "num_args" ], + [ "paren.lparen", "(" ], + [ "identifier", "int" ], + [ "paren.rparen", ")" ], + [ "paren.rparen", "}" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "qcomment1", + "data": [ + [ "comment", "--[=[--" ] + ] + }, + { + "state": "qcomment1", + "data": [ + [ "comment", "table.maxn is deprecated, use # instead." ] + ] + }, + { + "state": "start", + "data": [ + [ "comment", "--]=]" ], + [ "comment", "--" ] + ] + }, + { + "state": "start", + "data": [ + [ "support.function", "print" ], + [ "paren.lparen", "(" ], + [ "constant.library", "table" ], + [ "text", "." ], + [ "invalid.deprecated", "maxn" ], + [ "paren.lparen", "{" ], + [ "constant.numeric", "1" ], + [ "text", "," ], + [ "constant.numeric", "2" ], + [ "text", "," ], + [ "paren.lparen", "[" ], + [ "constant.numeric", "4" ], + [ "paren.rparen", "]" ], + [ "keyword.operator", "=" ], + [ "constant.numeric", "4" ], + [ "text", "," ], + [ "paren.lparen", "[" ], + [ "constant.numeric", "8" ], + [ "paren.rparen", "]" ], + [ "keyword.operator", "=" ], + [ "constant.numeric", "8" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "comment", "-- outputs 8 instead of 2" ] + ] + }, + { + "state": "start", + "data": [] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_luapage.json b/lib/ace/mode/_test/tokens_luapage.json new file mode 100644 index 0000000000..a6395ef055 --- /dev/null +++ b/lib/ace/mode/_test/tokens_luapage.json @@ -0,0 +1,824 @@ +[ + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", "" ], + [ "meta.tag", "<" ], + [ "text", "!" ], + [ "entity.other.attribute-name", "DOCTYPE" ], + [ "text", " " ], + [ "entity.other.attribute-name", "html" ], + [ "text", " " ], + [ "entity.other.attribute-name", "PUBLIC" ], + [ "text", " " ], + [ "string", "\"-//W3C//DTD XHTML 1.0 Strict//EN\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "string", "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "html" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "lua-qcomment", + "data": [ + [ "keyword", "<%" ], + [ "text", " " ], + [ "comment", "--[[--" ] + ] + }, + { + "state": "lua-qcomment", + "data": [ + [ "comment", " index.lp from the Kepler Project's LuaDoc HTML doclet." ] + ] + }, + { + "state": "lua-qcomment", + "data": [ + [ "comment", " http://keplerproject.github.com/luadoc/" ] + ] + }, + { + "state": "start", + "data": [ + [ "comment", "--]]" ], + [ "text", " " ], + [ "keyword", "%>" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "head" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "title" ], + [ "meta.tag", ">" ], + [ "text", "Reference" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "link" ], + [ "text", " " ], + [ "entity.other.attribute-name", "rel" ], + [ "keyword.operator", "=" ], + [ "string", "\"stylesheet\"" ], + [ "text", " " ], + [ "entity.other.attribute-name", "href" ], + [ "keyword.operator", "=" ], + [ "string", "\"<%=luadoc.doclet.html.link(\"" ], + [ "entity.other.attribute-name", "luadoc" ], + [ "text", "." ], + [ "entity.other.attribute-name", "css" ], + [ "string", "\")%>\"" ], + [ "text", " " ], + [ "entity.other.attribute-name", "type" ], + [ "keyword.operator", "=" ], + [ "string", "\"text/css\"" ], + [ "text", " " ], + [ "meta.tag", "/>" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "comment", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "body" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "div" ], + [ "text", " " ], + [ "entity.other.attribute-name", "id" ], + [ "keyword.operator", "=" ], + [ "string", "\"container\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "div" ], + [ "text", " " ], + [ "entity.other.attribute-name", "id" ], + [ "keyword.operator", "=" ], + [ "string", "\"product\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "div" ], + [ "text", " " ], + [ "entity.other.attribute-name", "id" ], + [ "keyword.operator", "=" ], + [ "string", "\"product_logo\"" ], + [ "meta.tag", ">" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "div" ], + [ "text", " " ], + [ "entity.other.attribute-name", "id" ], + [ "keyword.operator", "=" ], + [ "string", "\"product_name\"" ], + [ "meta.tag", ">" ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "big" ], + [ "meta.tag", ">" ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "b" ], + [ "meta.tag", ">" ], + [ "meta.tag", "" ], + [ "meta.tag", "" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "div" ], + [ "text", " " ], + [ "entity.other.attribute-name", "id" ], + [ "keyword.operator", "=" ], + [ "string", "\"product_description\"" ], + [ "meta.tag", ">" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "" ], + [ "text", " " ], + [ "comment", "" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "div" ], + [ "text", " " ], + [ "entity.other.attribute-name", "id" ], + [ "keyword.operator", "=" ], + [ "string", "\"main\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "div" ], + [ "text", " " ], + [ "entity.other.attribute-name", "id" ], + [ "keyword.operator", "=" ], + [ "string", "\"navigation\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "<%=" ], + [ "identifier", "luadoc" ], + [ "text", "." ], + [ "identifier", "doclet" ], + [ "text", "." ], + [ "identifier", "html" ], + [ "text", "." ], + [ "identifier", "include" ], + [ "paren.lparen", "(" ], + [ "string", "\"menu.lp\"" ], + [ "text", ", " ], + [ "paren.lparen", "{" ], + [ "text", " " ], + [ "identifier", "doc" ], + [ "keyword.operator", "=" ], + [ "identifier", "doc" ], + [ "text", " " ], + [ "paren.rparen", "}" ], + [ "paren.rparen", ")" ], + [ "keyword", "%>" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "" ], + [ "text", " " ], + [ "comment", "" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "div" ], + [ "text", " " ], + [ "entity.other.attribute-name", "id" ], + [ "keyword.operator", "=" ], + [ "string", "\"content\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "<%" ], + [ "keyword", "if" ], + [ "text", " " ], + [ "keyword", "not" ], + [ "text", " " ], + [ "identifier", "options" ], + [ "text", "." ], + [ "identifier", "nomodules" ], + [ "text", " " ], + [ "keyword", "and" ], + [ "text", " " ], + [ "keyword.operator", "#" ], + [ "identifier", "doc" ], + [ "text", "." ], + [ "identifier", "modules" ], + [ "text", " " ], + [ "keyword.operator", ">" ], + [ "text", " " ], + [ "constant.numeric", "0" ], + [ "text", " " ], + [ "keyword", "then" ], + [ "keyword", "%>" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "h2" ], + [ "meta.tag", ">" ], + [ "text", "Modules" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name.table", "table" ], + [ "text", " " ], + [ "entity.other.attribute-name", "class" ], + [ "keyword.operator", "=" ], + [ "string", "\"module_list\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "comment", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "<%" ], + [ "keyword", "for" ], + [ "text", " " ], + [ "identifier", "_" ], + [ "text", ", " ], + [ "identifier", "modulename" ], + [ "text", " " ], + [ "keyword", "in" ], + [ "text", " " ], + [ "support.function", "ipairs" ], + [ "paren.lparen", "(" ], + [ "identifier", "doc" ], + [ "text", "." ], + [ "identifier", "modules" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "keyword", "do" ], + [ "keyword", "%>" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name.table", "tr" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t\t" ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name.table", "td" ], + [ "text", " " ], + [ "entity.other.attribute-name", "class" ], + [ "keyword.operator", "=" ], + [ "string", "\"name\"" ], + [ "meta.tag", ">" ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name.anchor", "a" ], + [ "text", " " ], + [ "entity.other.attribute-name", "href" ], + [ "keyword.operator", "=" ], + [ "string", "\"<%=luadoc.doclet.html.module_link(modulename, doc)%>\"" ], + [ "meta.tag", ">" ], + [ "keyword", "<%=" ], + [ "identifier", "modulename" ], + [ "keyword", "%>" ], + [ "meta.tag", "" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t\t" ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name.table", "td" ], + [ "text", " " ], + [ "entity.other.attribute-name", "class" ], + [ "keyword.operator", "=" ], + [ "string", "\"summary\"" ], + [ "meta.tag", ">" ], + [ "keyword", "<%=" ], + [ "identifier", "doc" ], + [ "text", "." ], + [ "identifier", "modules" ], + [ "paren.lparen", "[" ], + [ "identifier", "modulename" ], + [ "paren.rparen", "]" ], + [ "text", "." ], + [ "identifier", "summary" ], + [ "keyword", "%>" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "<%" ], + [ "keyword", "end" ], + [ "keyword", "%>" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "<%" ], + [ "keyword", "end" ], + [ "keyword", "%>" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "<%" ], + [ "keyword", "if" ], + [ "text", " " ], + [ "keyword", "not" ], + [ "text", " " ], + [ "identifier", "options" ], + [ "text", "." ], + [ "identifier", "nofiles" ], + [ "text", " " ], + [ "keyword", "and" ], + [ "text", " " ], + [ "keyword.operator", "#" ], + [ "identifier", "doc" ], + [ "text", "." ], + [ "identifier", "files" ], + [ "text", " " ], + [ "keyword.operator", ">" ], + [ "text", " " ], + [ "constant.numeric", "0" ], + [ "text", " " ], + [ "keyword", "then" ], + [ "keyword", "%>" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "h2" ], + [ "meta.tag", ">" ], + [ "text", "Files" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name.table", "table" ], + [ "text", " " ], + [ "entity.other.attribute-name", "class" ], + [ "keyword.operator", "=" ], + [ "string", "\"file_list\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "comment", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "<%" ], + [ "keyword", "for" ], + [ "text", " " ], + [ "identifier", "_" ], + [ "text", ", " ], + [ "identifier", "filepath" ], + [ "text", " " ], + [ "keyword", "in" ], + [ "text", " " ], + [ "support.function", "ipairs" ], + [ "paren.lparen", "(" ], + [ "identifier", "doc" ], + [ "text", "." ], + [ "identifier", "files" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "keyword", "do" ], + [ "keyword", "%>" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name.table", "tr" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t\t" ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name.table", "td" ], + [ "text", " " ], + [ "entity.other.attribute-name", "class" ], + [ "keyword.operator", "=" ], + [ "string", "\"name\"" ], + [ "meta.tag", ">" ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name.anchor", "a" ], + [ "text", " " ], + [ "entity.other.attribute-name", "href" ], + [ "keyword.operator", "=" ], + [ "string", "\"<%=luadoc.doclet.html.file_link(filepath)%>\"" ], + [ "meta.tag", ">" ], + [ "keyword", "<%=" ], + [ "identifier", "filepath" ], + [ "keyword", "%>" ], + [ "meta.tag", "" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t\t" ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name.table", "td" ], + [ "text", " " ], + [ "entity.other.attribute-name", "class" ], + [ "keyword.operator", "=" ], + [ "string", "\"summary\"" ], + [ "meta.tag", ">" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "<%" ], + [ "keyword", "end" ], + [ "keyword", "%>" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "<%" ], + [ "keyword", "end" ], + [ "keyword", "%>" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "" ], + [ "text", " " ], + [ "comment", "" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "" ], + [ "text", " " ], + [ "comment", "" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "div" ], + [ "text", " " ], + [ "entity.other.attribute-name", "id" ], + [ "keyword.operator", "=" ], + [ "string", "\"about\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "p" ], + [ "meta.tag", ">" ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name.anchor", "a" ], + [ "text", " " ], + [ "entity.other.attribute-name", "href" ], + [ "keyword.operator", "=" ], + [ "string", "\"http://validator.w3.org/check?uri=referer\"" ], + [ "meta.tag", ">" ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name.image", "img" ], + [ "text", " " ], + [ "entity.other.attribute-name", "src" ], + [ "keyword.operator", "=" ], + [ "string", "\"http://www.w3.org/Icons/valid-xhtml10\"" ], + [ "text", " " ], + [ "entity.other.attribute-name", "alt" ], + [ "keyword.operator", "=" ], + [ "string", "\"Valid XHTML 1.0!\"" ], + [ "text", " " ], + [ "entity.other.attribute-name", "height" ], + [ "keyword.operator", "=" ], + [ "string", "\"31\"" ], + [ "text", " " ], + [ "entity.other.attribute-name", "width" ], + [ "keyword.operator", "=" ], + [ "string", "\"88\"" ], + [ "text", " " ], + [ "meta.tag", "/>" ], + [ "meta.tag", "" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "" ], + [ "text", " " ], + [ "comment", "" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "" ], + [ "text", " " ], + [ "comment", "" ], + [ "text", "\t" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_markdown.json b/lib/ace/mode/_test/tokens_markdown.json new file mode 100644 index 0000000000..02e22c004d --- /dev/null +++ b/lib/ace/mode/_test/tokens_markdown.json @@ -0,0 +1,1202 @@ +[ + { + "state": "start", + "data": [ + [ "text", "Ace (Ajax.org Cloud9 Editor)" ] + ] + }, + { + "state": "start", + "data": [ + [ "markup.heading.1", "============================" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Ace is a standalone code editor written in JavaScript. Our goal is to create a browser based editor that matches and extends the features, usability and performance of existing native editors such as TextMate, Vim or Eclipse. It can be easily embedded in any web page or JavaScript application. Ace is developed as the primary editor for [" ], + [ "string", "Cloud9 IDE" ], + [ "text", "](" ], + [ "markup.underline", "http://www.cloud9ide.com/" ], + [ "text", ") and the successor of the Mozilla Skywriter (Bespin) Project." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Features" ] + ] + }, + { + "state": "start", + "data": [ + [ "markup.heading.2", "--------" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "listblock", + "data": [ + [ "markup.list", "* " ], + [ "markup.list", "Syntax highlighting" ] + ] + }, + { + "state": "listblock", + "data": [ + [ "markup.list", "* Automatic indent and outdent" ] + ] + }, + { + "state": "listblock", + "data": [ + [ "markup.list", "* An optional command line" ] + ] + }, + { + "state": "listblock", + "data": [ + [ "markup.list", "* Handles huge documents (100,000 lines and more are no problem)" ] + ] + }, + { + "state": "listblock", + "data": [ + [ "markup.list", "* Fully customizable key bindings including VI and Emacs modes" ] + ] + }, + { + "state": "listblock", + "data": [ + [ "markup.list", "* Themes (TextMate themes can be imported)" ] + ] + }, + { + "state": "listblock", + "data": [ + [ "markup.list", "* Search and replace with regular expressions" ] + ] + }, + { + "state": "listblock", + "data": [ + [ "markup.list", "* Highlight matching parentheses" ] + ] + }, + { + "state": "listblock", + "data": [ + [ "markup.list", "* Toggle between soft tabs and real tabs" ] + ] + }, + { + "state": "listblock", + "data": [ + [ "markup.list", "* Displays hidden characters" ] + ] + }, + { + "state": "listblock", + "data": [ + [ "markup.list", "* Drag and drop text using the mouse" ] + ] + }, + { + "state": "listblock", + "data": [ + [ "markup.list", "* Line wrapping" ] + ] + }, + { + "state": "listblock", + "data": [ + [ "markup.list", "* Unstructured / user code folding" ] + ] + }, + { + "state": "listblock", + "data": [ + [ "markup.list", "* Live syntax checker (currently JavaScript/CoffeeScript)" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Take Ace for a spin!" ] + ] + }, + { + "state": "start", + "data": [ + [ "markup.heading.2", "--------------------" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Check out the Ace live [" ], + [ "string", "demo" ], + [ "text", "](" ], + [ "markup.underline", "http://ajaxorg.github.com/ace/" ], + [ "text", ") or get a [" ], + [ "string", "Cloud9 IDE account" ], + [ "text", "](" ], + [ "markup.underline", "http://run.cloud9ide.com" ], + [ "text", ") to experience Ace while editing one of your own GitHub projects." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "If you want, you can use Ace as a textarea replacement thanks to the [" ], + [ "string", "Ace Bookmarklet" ], + [ "text", "](" ], + [ "markup.underline", "http://ajaxorg.github.com/ace/build/textarea/editor.html" ], + [ "text", ")." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "History" ] + ] + }, + { + "state": "start", + "data": [ + [ "markup.heading.2", "-------" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Previously known as “Bespin” and “Skywriter” it’s now known as Ace (Ajax.org Cloud9 Editor)! Bespin and Ace started as two independent projects, both aiming to build a no-compromise code editor component for the web. Bespin started as part of Mozilla Labs and was based on the canvas tag, while Ace is the Editor component of the Cloud9 IDE and is using the DOM for rendering. After the release of Ace at JSConf.eu 2010 in Berlin the Skywriter team decided to merge Ace with a simplified version of Skywriter's plugin system and some of Skywriter's extensibility points. All these changes have been merged back to Ace. Both Ajax.org and Mozilla are actively developing and maintaining Ace." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Getting the code" ] + ] + }, + { + "state": "start", + "data": [ + [ "markup.heading.2", "----------------" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Ace is a community project. We actively encourage and support contributions. The Ace source code is hosted on GitHub. It is released under the BSD License. This license is very simple, and is friendly to all kinds of projects, whether open source or not. Take charge of your editor and add your favorite language highlighting and keybindings!" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "githubblock", + "data": [ + [ "support.function", "```bash" ] + ] + }, + { + "state": "githubblock", + "data": [ + [ "support.function", " git clone git://github.com/ajaxorg/ace.git" ] + ] + }, + { + "state": "githubblock", + "data": [ + [ "support.function", " cd ace" ] + ] + }, + { + "state": "githubblock", + "data": [ + [ "support.function", " git submodule update --init --recursive" ] + ] + }, + { + "state": "start", + "data": [ + [ "support.function", "```" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Embedding Ace" ] + ] + }, + { + "state": "start", + "data": [ + [ "markup.heading.2", "-------------" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Ace can be easily embedded into any existing web page. The Ace git repository ships with a pre-packaged version of Ace inside of the " ], + [ "support.function", "`" ], + [ "support.function", "build" ], + [ "support.function", "`" ], + [ "text", " directory. The same packaged files are also available as a separate [" ], + [ "string", "download" ], + [ "text", "](" ], + [ "markup.underline", "https://github.com/ajaxorg/ace/downloads" ], + [ "text", "). Simply copy the contents of the " ], + [ "support.function", "`" ], + [ "support.function", "src" ], + [ "support.function", "`" ], + [ "text", " subdirectory somewhere into your project and take a look at the included demos of how to use Ace." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "The easiest version is simply:" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "html-start", + "data": [ + [ "support.function", "```html" ] + ] + }, + { + "state": "html-start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "div" ], + [ "text", " " ], + [ "entity.other.attribute-name", "id" ], + [ "keyword.operator", "=" ], + [ "string", "\"editor\"" ], + [ "meta.tag", ">" ], + [ "text", "some text" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "html-start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name.script", "script" ], + [ "text", " " ], + [ "entity.other.attribute-name", "src" ], + [ "keyword.operator", "=" ], + [ "string", "\"src/ace.js\"" ], + [ "text", " " ], + [ "entity.other.attribute-name", "type" ], + [ "keyword.operator", "=" ], + [ "string", "\"text/javascript\"" ], + [ "text", " " ], + [ "entity.other.attribute-name", "charset" ], + [ "keyword.operator", "=" ], + [ "string", "\"utf-8\"" ], + [ "meta.tag", ">" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "html-js-start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name.script", "script" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "html-js-regex_allowed", + "data": [ + [ "text", " " ], + [ "storage.type", "window" ], + [ "punctuation.operator", "." ], + [ "entity.name.function", "onload" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "storage.type", "function" ], + [ "paren.lparen", "(" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "html-js-regex_allowed", + "data": [ + [ "text", " " ], + [ "storage.type", "var" ], + [ "text", " " ], + [ "identifier", "editor" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "identifier", "ace" ], + [ "punctuation.operator", "." ], + [ "identifier", "edit" ], + [ "paren.lparen", "(" ], + [ "string", "\"editor\"" ], + [ "paren.rparen", ")" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "html-js-regex_allowed", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "html-start", + "data": [ + [ "text", " " ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "support.function", "```" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "With \"editor\" being the id of the DOM element, which should be converted to an editor. Note that this element must be explicitly sized and positioned " ], + [ "support.function", "`" ], + [ "support.function", "absolute" ], + [ "support.function", "`" ], + [ "text", " or " ], + [ "support.function", "`" ], + [ "support.function", "relative" ], + [ "support.function", "`" ], + [ "text", " for Ace to work. e.g." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "css-start", + "data": [ + [ "support.function", "```css" ] + ] + }, + { + "state": "css-ruleset", + "data": [ + [ "text", " " ], + [ "keyword", "#editor" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "css-ruleset", + "data": [ + [ "text", " " ], + [ "support.type", "position" ], + [ "text", ": " ], + [ "support.constant", "absolute" ], + [ "text", ";" ] + ] + }, + { + "state": "css-ruleset", + "data": [ + [ "text", " " ], + [ "support.type", "width" ], + [ "text", ": " ], + [ "constant.numeric", "500" ], + [ "keyword", "px" ], + [ "text", ";" ] + ] + }, + { + "state": "css-ruleset", + "data": [ + [ "text", " " ], + [ "support.type", "height" ], + [ "text", ": " ], + [ "constant.numeric", "400" ], + [ "keyword", "px" ], + [ "text", ";" ] + ] + }, + { + "state": "css-start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "support.function", "```" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "To change the theme simply include the Theme's JavaScript file" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "html-start", + "data": [ + [ "support.function", "```html" ] + ] + }, + { + "state": "html-start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name.script", "script" ], + [ "text", " " ], + [ "entity.other.attribute-name", "src" ], + [ "keyword.operator", "=" ], + [ "string", "\"src/theme-twilight.js\"" ], + [ "text", " " ], + [ "entity.other.attribute-name", "type" ], + [ "keyword.operator", "=" ], + [ "string", "\"text/javascript\"" ], + [ "text", " " ], + [ "entity.other.attribute-name", "charset" ], + [ "keyword.operator", "=" ], + [ "string", "\"utf-8\"" ], + [ "meta.tag", ">" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "support.function", "```" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "and configure the editor to use the theme:" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "js-start", + "data": [ + [ "support.function", "```javascript" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "identifier", "editor" ], + [ "punctuation.operator", "." ], + [ "identifier", "setTheme" ], + [ "paren.lparen", "(" ], + [ "string", "\"ace/theme/twilight\"" ], + [ "paren.rparen", ")" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "support.function", "```" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "By default the editor only supports plain text mode; many other languages are available as separate modules. After including the mode's JavaScript file:" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "html-start", + "data": [ + [ "support.function", "```html" ] + ] + }, + { + "state": "html-start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name.script", "script" ], + [ "text", " " ], + [ "entity.other.attribute-name", "src" ], + [ "keyword.operator", "=" ], + [ "string", "\"src/mode-javascript.js\"" ], + [ "text", " " ], + [ "entity.other.attribute-name", "type" ], + [ "keyword.operator", "=" ], + [ "string", "\"text/javascript\"" ], + [ "text", " " ], + [ "entity.other.attribute-name", "charset" ], + [ "keyword.operator", "=" ], + [ "string", "\"utf-8\"" ], + [ "meta.tag", ">" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "support.function", "```" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Then the mode can be used like this:" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "js-start", + "data": [ + [ "support.function", "```javascript" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "storage.type", "var" ], + [ "text", " " ], + [ "identifier", "JavaScriptMode" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "identifier", "require" ], + [ "paren.lparen", "(" ], + [ "string", "\"ace/mode/javascript\"" ], + [ "paren.rparen", ")" ], + [ "punctuation.operator", "." ], + [ "identifier", "Mode" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "identifier", "editor" ], + [ "punctuation.operator", "." ], + [ "identifier", "getSession" ], + [ "paren.lparen", "(" ], + [ "paren.rparen", ")" ], + [ "punctuation.operator", "." ], + [ "identifier", "setMode" ], + [ "paren.lparen", "(" ], + [ "keyword", "new" ], + [ "text", " " ], + [ "identifier", "JavaScriptMode" ], + [ "paren.lparen", "(" ], + [ "paren.rparen", ")" ], + [ "paren.rparen", ")" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "support.function", "```" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Documentation" ] + ] + }, + { + "state": "start", + "data": [ + [ "markup.heading.2", "-------------" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "You find a lot more sample code in the [" ], + [ "string", "demo app" ], + [ "text", "](" ], + [ "markup.underline", "https://github.com/ajaxorg/ace/blob/master/demo/demo.js" ], + [ "text", ")." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "There is also some documentation on the [" ], + [ "string", "wiki page" ], + [ "text", "](" ], + [ "markup.underline", "https://github.com/ajaxorg/ace/wiki" ], + [ "text", ")." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "If you still need help, feel free to drop a mail on the [" ], + [ "string", "ace mailing list" ], + [ "text", "](" ], + [ "markup.underline", "http://groups.google.com/group/ace-discuss" ], + [ "text", ")." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Running Ace" ] + ] + }, + { + "state": "start", + "data": [ + [ "markup.heading.2", "-----------" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "After the checkout Ace works out of the box. No build step is required. Open 'editor.html' in any browser except Google Chrome. Google Chrome doesn't allow XMLHTTPRequests from files loaded from disc (i.e. with a file:/// URL). To open Ace in Chrome simply start the bundled mini HTTP server:" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "githubblock", + "data": [ + [ "support.function", "```bash" ] + ] + }, + { + "state": "githubblock", + "data": [ + [ "support.function", " ./static.py" ] + ] + }, + { + "state": "start", + "data": [ + [ "support.function", "```" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Or using Node.JS" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "githubblock", + "data": [ + [ "support.function", "```bash" ] + ] + }, + { + "state": "githubblock", + "data": [ + [ "support.function", " ./static.js" ] + ] + }, + { + "state": "start", + "data": [ + [ "support.function", "```" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "The editor can then be opened at http://localhost:8888/index.html." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Package Ace" ] + ] + }, + { + "state": "start", + "data": [ + [ "markup.heading.2", "-----------" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "To package Ace we use the dryice build tool developed by the Mozilla Skywriter team. Before you can build you need to make sure that the submodules are up to date." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "githubblock", + "data": [ + [ "support.function", "```bash" ] + ] + }, + { + "state": "githubblock", + "data": [ + [ "support.function", " git submodule update --init --recursive" ] + ] + }, + { + "state": "start", + "data": [ + [ "support.function", "```" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Afterwards Ace can be built by calling" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "githubblock", + "data": [ + [ "support.function", "```bash" ] + ] + }, + { + "state": "githubblock", + "data": [ + [ "support.function", " ./Makefile.dryice.js normal" ] + ] + }, + { + "state": "start", + "data": [ + [ "support.function", "```" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "The packaged Ace will be put in the 'build' folder." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "To build the bookmarklet version execute" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "githubblock", + "data": [ + [ "support.function", "```bash" ] + ] + }, + { + "state": "githubblock", + "data": [ + [ "support.function", " ./Makefile.dryice.js bm" ] + ] + }, + { + "state": "start", + "data": [ + [ "support.function", "```" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Running the Unit Tests" ] + ] + }, + { + "state": "start", + "data": [ + [ "markup.heading.2", "----------------------" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "The Ace unit tests run on node.js. Before the first run a couple of node modules have to be installed. The easiest way to do this is by using the node package manager (npm). In the Ace base directory simply call" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "githubblock", + "data": [ + [ "support.function", "```bash" ] + ] + }, + { + "state": "githubblock", + "data": [ + [ "support.function", " npm link ." ] + ] + }, + { + "state": "start", + "data": [ + [ "support.function", "```" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "To run the tests call:" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "githubblock", + "data": [ + [ "support.function", "```bash" ] + ] + }, + { + "state": "githubblock", + "data": [ + [ "support.function", " node lib/ace/test/all.js" ] + ] + }, + { + "state": "start", + "data": [ + [ "support.function", "```" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "You can also run the tests in your browser by serving:" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.function", " http://localhost:8888/lib/ace/test/tests.html" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "This makes debugging failing tests way more easier." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Contributing" ] + ] + }, + { + "state": "start", + "data": [ + [ "markup.heading.2", "------------" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Ace wouldn't be what it is without contributions! Feel free to fork and improve/enhance Ace any way you want. If you feel that the editor or the Ace community will benefit from your changes, please open a pull request. To protect the interests of the Ace contributors and users we require contributors to sign a Contributors License Agreement (CLA) before we pull the changes into the main repository. Our CLA is the simplest of agreements, requiring that the contributions you make to an ajax.org project are only those you're allowed to make. This helps us significantly reduce future legal risk for everyone involved. It is easy, helps everyone, takes ten minutes, and only needs to be completed once. There are two versions of the agreement:" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "listblock", + "data": [ + [ "markup.list", "1. " ], + [ "markup.list", "[The Individual CLA](https://github.com/ajaxorg/ace/raw/master/doc/Contributor_License_Agreement-v2.pdf): use this version if you're working on an ajax.org in your spare time, or can clearly claim ownership of copyright in what you'll be submitting." ] + ] + }, + { + "state": "listblock", + "data": [ + [ "markup.list", "2. [The Corporate CLA](https://github.com/ajaxorg/ace/raw/master/doc/Corporate_Contributor_License_Agreement-v2.pdf): have your corporate lawyer review and submit this if your company is going to be contributing to ajax.org projects" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "If you want to contribute to an ajax.org project please print the CLA and fill it out and sign it. Then either send it by snail mail or fax to us or send it back scanned (or as a photo) by email." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Email: fabian.jakobs@web.de" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Fax: +31 (0) 206388953" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Address: Ajax.org B.V." ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " Keizersgracht 241" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " 1016 EA, Amsterdam" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " the Netherlands" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_ocaml.json b/lib/ace/mode/_test/tokens_ocaml.json new file mode 100644 index 0000000000..fa5055c45e --- /dev/null +++ b/lib/ace/mode/_test/tokens_ocaml.json @@ -0,0 +1,260 @@ +[ + { + "state": "comment", + "data": [ + [ "comment", "(*" ] + ] + }, + { + "state": "comment", + "data": [ + [ "comment", " * Example of early return implementation taken from" ] + ] + }, + { + "state": "comment", + "data": [ + [ "comment", " * http://ocaml.janestreet.com/?q=node/91" ] + ] + }, + { + "state": "start", + "data": [ + [ "comment", " *)" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "let" ], + [ "text", " " ], + [ "identifier", "with_return" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "keyword", "type" ], + [ "text", " " ], + [ "identifier", "t" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "identifier", "f" ], + [ "text", " : " ], + [ "identifier", "_" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "keyword.operator", ">" ], + [ "text", " " ], + [ "identifier", "t" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "keyword.operator", "=" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "let" ], + [ "text", " " ], + [ "keyword", "module" ], + [ "text", " " ], + [ "identifier", "M" ], + [ "text", " " ], + [ "keyword.operator", "=" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "struct" ], + [ "text", " " ], + [ "keyword", "exception" ], + [ "text", " " ], + [ "identifier", "Return" ], + [ "text", " " ], + [ "keyword", "of" ], + [ "text", " " ], + [ "identifier", "t" ], + [ "text", " " ], + [ "keyword", "end" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "in" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "let" ], + [ "text", " " ], + [ "identifier", "return" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "paren.lparen", "{" ], + [ "text", " " ], + [ "identifier", "return" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "keyword", "fun" ], + [ "text", " " ], + [ "identifier", "x" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "keyword.operator", ">" ], + [ "text", " " ], + [ "support.function", "raise" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "identifier", "M" ], + [ "text", "." ], + [ "identifier", "Return" ], + [ "text", " " ], + [ "identifier", "x" ], + [ "paren.rparen", ")" ], + [ "paren.rparen", ")" ], + [ "text", "; " ], + [ "paren.rparen", "}" ], + [ "text", " " ], + [ "keyword", "in" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "try" ], + [ "text", " " ], + [ "identifier", "f" ], + [ "text", " " ], + [ "identifier", "return" ], + [ "text", " " ], + [ "keyword", "with" ], + [ "text", " " ], + [ "identifier", "M" ], + [ "text", "." ], + [ "identifier", "Return" ], + [ "text", " " ], + [ "identifier", "x" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "keyword.operator", ">" ], + [ "text", " " ], + [ "identifier", "x" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "comment", "(* Function that uses the 'early return' functionality provided by `with_return` *)" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "let" ], + [ "text", " " ], + [ "identifier", "sum_until_first_negative" ], + [ "text", " " ], + [ "support.function", "list" ], + [ "text", " " ], + [ "keyword.operator", "=" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "with_return" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "keyword", "fun" ], + [ "text", " " ], + [ "identifier", "r" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "keyword.operator", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "support.function", "List" ], + [ "text", "." ], + [ "support.function", "fold" ], + [ "text", " " ], + [ "support.function", "list" ], + [ "text", " " ], + [ "keyword.operator", "~" ], + [ "support.function", "init" ], + [ "text", ":" ], + [ "constant.numeric", "0" ], + [ "text", " " ], + [ "keyword.operator", "~" ], + [ "identifier", "f" ], + [ "text", ":" ], + [ "paren.lparen", "(" ], + [ "keyword", "fun" ], + [ "text", " " ], + [ "identifier", "acc" ], + [ "text", " " ], + [ "identifier", "x" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "keyword.operator", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "identifier", "x" ], + [ "text", " " ], + [ "keyword.operator", ">" ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "constant.numeric", "0" ], + [ "text", " " ], + [ "keyword", "then" ], + [ "text", " " ], + [ "identifier", "acc" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "text", " " ], + [ "identifier", "x" ], + [ "text", " " ], + [ "keyword", "else" ], + [ "text", " " ], + [ "identifier", "r" ], + [ "text", "." ], + [ "identifier", "return" ], + [ "text", " " ], + [ "identifier", "acc" ], + [ "paren.rparen", ")" ], + [ "paren.rparen", ")" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_perl.json b/lib/ace/mode/_test/tokens_perl.json new file mode 100644 index 0000000000..fb33da272c --- /dev/null +++ b/lib/ace/mode/_test/tokens_perl.json @@ -0,0 +1,311 @@ +[ + { + "state": "start", + "data": [ + [ "comment", "#!/usr/bin/perl" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "use" ], + [ "text", " " ], + [ "identifier", "strict" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "use" ], + [ "text", " " ], + [ "identifier", "warnings" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "my" ], + [ "text", " " ], + [ "identifier", "$num_primes" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "constant.numeric", "0" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "my" ], + [ "text", " @" ], + [ "identifier", "primes" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "comment", "# Put 2 as the first prime so we won't have an empty array" ] + ] + }, + { + "state": "start", + "data": [ + [ "identifier", "$primes" ], + [ "lparen", "[" ], + [ "identifier", "$num_primes" ], + [ "rparen", "]" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "constant.numeric", "2" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "identifier", "$num_primes" ], + [ "keyword.operator", "++" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "identifier", "MAIN_LOOP" ], + [ "text", ":" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "for" ], + [ "text", " " ], + [ "keyword", "my" ], + [ "text", " " ], + [ "identifier", "$number_to_check" ], + [ "text", " " ], + [ "lparen", "(" ], + [ "constant.numeric", "3" ], + [ "text", " " ], + [ "keyword.operator", ".." ], + [ "text", " " ], + [ "constant.numeric", "200" ], + [ "rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "for" ], + [ "text", " " ], + [ "keyword", "my" ], + [ "text", " " ], + [ "identifier", "$p" ], + [ "text", " " ], + [ "lparen", "(" ], + [ "constant.numeric", "0" ], + [ "text", " " ], + [ "keyword.operator", ".." ], + [ "text", " " ], + [ "lparen", "(" ], + [ "identifier", "$num_primes" ], + [ "constant.numeric", "-1" ], + [ "rparen", ")" ], + [ "rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "lparen", "(" ], + [ "identifier", "$number_to_check" ], + [ "text", " " ], + [ "keyword.operator", "%" ], + [ "text", " " ], + [ "identifier", "$primes" ], + [ "lparen", "[" ], + [ "identifier", "$p" ], + [ "rparen", "]" ], + [ "text", " " ], + [ "keyword.operator", "==" ], + [ "text", " " ], + [ "constant.numeric", "0" ], + [ "rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "next" ], + [ "text", " " ], + [ "identifier", "MAIN_LOOP" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "comment", "# If we reached this point it means $number_to_check is not" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "comment", "# divisable by any prime number that came before it." ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "$primes" ], + [ "lparen", "[" ], + [ "identifier", "$num_primes" ], + [ "rparen", "]" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "identifier", "$number_to_check" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "$num_primes" ], + [ "keyword.operator", "++" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "for" ], + [ "text", " " ], + [ "keyword", "my" ], + [ "text", " " ], + [ "identifier", "$p" ], + [ "text", " " ], + [ "lparen", "(" ], + [ "constant.numeric", "0" ], + [ "text", " " ], + [ "keyword.operator", ".." ], + [ "text", " " ], + [ "lparen", "(" ], + [ "identifier", "$num_primes" ], + [ "constant.numeric", "-1" ], + [ "rparen", ")" ], + [ "rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "support.function", "print" ], + [ "text", " " ], + [ "identifier", "$primes" ], + [ "lparen", "[" ], + [ "identifier", "$p" ], + [ "rparen", "]" ], + [ "keyword.operator", "," ], + [ "text", " " ], + [ "string", "\", \"" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "support.function", "print" ], + [ "text", " " ], + [ "string", "\"\\n\"" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_pgsql.json b/lib/ace/mode/_test/tokens_pgsql.json new file mode 100644 index 0000000000..6e6630930d --- /dev/null +++ b/lib/ace/mode/_test/tokens_pgsql.json @@ -0,0 +1,1020 @@ +[ + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword.statementBegin", "BEGIN" ], + [ "statementEnd", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "doc-start", + "data": [ + [ "comment.doc", "/**" ] + ] + }, + { + "state": "doc-start", + "data": [ + [ "comment.doc", "* Samples from PostgreSQL src/tutorial/basics.source" ] + ] + }, + { + "state": "start", + "data": [ + [ "comment.doc", "*/" ] + ] + }, + { + "state": "statement", + "data": [ + [ "keyword.statementBegin", "CREATE" ], + [ "text", " " ], + [ "keyword", "TABLE" ], + [ "text", " " ], + [ "identifier", "weather" ], + [ "text", " " ], + [ "paren.lparen", "(" ] + ] + }, + { + "state": "statement", + "data": [ + [ "text", "\t" ], + [ "identifier", "city" ], + [ "text", "\t\t" ], + [ "keyword", "varchar" ], + [ "paren.lparen", "(" ], + [ "constant.numeric", "80" ], + [ "paren.rparen", ")" ], + [ "text", "," ] + ] + }, + { + "state": "statement", + "data": [ + [ "text", "\t" ], + [ "identifier", "temp_lo" ], + [ "text", "\t\t" ], + [ "keyword", "int" ], + [ "text", ",\t\t" ], + [ "comment", "-- low temperature" ] + ] + }, + { + "state": "statement", + "data": [ + [ "text", "\t" ], + [ "identifier", "temp_hi" ], + [ "text", "\t\t" ], + [ "keyword", "int" ], + [ "text", ",\t\t" ], + [ "comment", "-- high temperature" ] + ] + }, + { + "state": "statement", + "data": [ + [ "text", "\t" ], + [ "identifier", "prcp" ], + [ "text", "\t\t" ], + [ "keyword", "real" ], + [ "text", ",\t\t" ], + [ "comment", "-- precipitation" ] + ] + }, + { + "state": "statement", + "data": [ + [ "text", "\t" ], + [ "variable.language", "\"date\"" ], + [ "text", "\t\t" ], + [ "keyword", "date" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", ")" ], + [ "statementEnd", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "statement", + "data": [ + [ "keyword.statementBegin", "CREATE" ], + [ "text", " " ], + [ "keyword", "TABLE" ], + [ "text", " " ], + [ "identifier", "cities" ], + [ "text", " " ], + [ "paren.lparen", "(" ] + ] + }, + { + "state": "statement", + "data": [ + [ "text", "\t" ], + [ "keyword", "name" ], + [ "text", "\t\t" ], + [ "keyword", "varchar" ], + [ "paren.lparen", "(" ], + [ "constant.numeric", "80" ], + [ "paren.rparen", ")" ], + [ "text", "," ] + ] + }, + { + "state": "statement", + "data": [ + [ "text", "\t" ], + [ "keyword", "location" ], + [ "text", "\t" ], + [ "keyword", "point" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", ")" ], + [ "statementEnd", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "statement", + "data": [ + [ "keyword.statementBegin", "INSERT" ], + [ "text", " " ], + [ "keyword", "INTO" ], + [ "text", " " ], + [ "identifier", "weather" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "VALUES" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "string", "'San Francisco'" ], + [ "text", ", " ], + [ "constant.numeric", "46" ], + [ "text", ", " ], + [ "constant.numeric", "50" ], + [ "text", ", " ], + [ "constant.numeric", "0.25" ], + [ "text", ", " ], + [ "string", "'1994-11-27'" ], + [ "paren.rparen", ")" ], + [ "statementEnd", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "statement", + "data": [ + [ "keyword.statementBegin", "INSERT" ], + [ "text", " " ], + [ "keyword", "INTO" ], + [ "text", " " ], + [ "identifier", "cities" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "VALUES" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "string", "'San Francisco'" ], + [ "text", ", " ], + [ "string", "'(-194.0, 53.0)'" ], + [ "paren.rparen", ")" ], + [ "statementEnd", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "statement", + "data": [ + [ "keyword.statementBegin", "INSERT" ], + [ "text", " " ], + [ "keyword", "INTO" ], + [ "text", " " ], + [ "identifier", "weather" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "identifier", "city" ], + [ "text", ", " ], + [ "identifier", "temp_lo" ], + [ "text", ", " ], + [ "identifier", "temp_hi" ], + [ "text", ", " ], + [ "identifier", "prcp" ], + [ "text", ", " ], + [ "variable.language", "\"date\"" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "VALUES" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "string", "'San Francisco'" ], + [ "text", ", " ], + [ "constant.numeric", "43" ], + [ "text", ", " ], + [ "constant.numeric", "57" ], + [ "text", ", " ], + [ "constant.numeric", "0.0" ], + [ "text", ", " ], + [ "string", "'1994-11-29'" ], + [ "paren.rparen", ")" ], + [ "statementEnd", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "statement", + "data": [ + [ "keyword.statementBegin", "INSERT" ], + [ "text", " " ], + [ "keyword", "INTO" ], + [ "text", " " ], + [ "identifier", "weather" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "keyword", "date" ], + [ "text", ", " ], + [ "identifier", "city" ], + [ "text", ", " ], + [ "identifier", "temp_hi" ], + [ "text", ", " ], + [ "identifier", "temp_lo" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "VALUES" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "string", "'1994-11-29'" ], + [ "text", ", " ], + [ "string", "'Hayward'" ], + [ "text", ", " ], + [ "constant.numeric", "54" ], + [ "text", ", " ], + [ "constant.numeric", "37" ], + [ "paren.rparen", ")" ], + [ "statementEnd", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword.statementBegin", "SELECT" ], + [ "text", " " ], + [ "identifier", "city" ], + [ "text", ", " ], + [ "paren.lparen", "(" ], + [ "identifier", "temp_hi" ], + [ "keyword.operator", "+" ], + [ "identifier", "temp_lo" ], + [ "paren.rparen", ")" ], + [ "keyword.operator", "/" ], + [ "constant.numeric", "2" ], + [ "text", " " ], + [ "keyword", "AS" ], + [ "text", " " ], + [ "identifier", "temp_avg" ], + [ "text", ", " ], + [ "variable.language", "\"date\"" ], + [ "text", " " ], + [ "keyword", "FROM" ], + [ "text", " " ], + [ "identifier", "weather" ], + [ "statementEnd", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "statement", + "data": [ + [ "keyword.statementBegin", "SELECT" ], + [ "text", " " ], + [ "identifier", "city" ], + [ "text", ", " ], + [ "identifier", "temp_lo" ], + [ "text", ", " ], + [ "identifier", "temp_hi" ], + [ "text", ", " ], + [ "identifier", "prcp" ], + [ "text", ", " ], + [ "variable.language", "\"date\"" ], + [ "text", ", " ], + [ "keyword", "location" ] + ] + }, + { + "state": "statement", + "data": [ + [ "text", " " ], + [ "keyword", "FROM" ], + [ "text", " " ], + [ "identifier", "weather" ], + [ "text", ", " ], + [ "identifier", "cities" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "WHERE" ], + [ "text", " " ], + [ "identifier", "city" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "keyword", "name" ], + [ "statementEnd", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "doc-start", + "data": [ + [ "comment.doc", "/**" ] + ] + }, + { + "state": "doc-start", + "data": [ + [ "comment.doc", "* Dollar quotes starting at the end of the line are colored as SQL unless" ] + ] + }, + { + "state": "doc-start", + "data": [ + [ "comment.doc", "* a special language tag is used. Pearl and Python are currently implemented" ] + ] + }, + { + "state": "doc-start", + "data": [ + [ "comment.doc", "* but lots of others are possible." ] + ] + }, + { + "state": "start", + "data": [ + [ "comment.doc", "*/" ] + ] + }, + { + "state": "statement", + "data": [ + [ "keyword.statementBegin", "create" ], + [ "text", " " ], + [ "keyword", "or" ], + [ "text", " " ], + [ "keyword", "replace" ], + [ "text", " " ], + [ "keyword", "function" ], + [ "text", " " ], + [ "identifier", "blob_content_chunked" ], + [ "paren.lparen", "(" ] + ] + }, + { + "state": "statement", + "data": [ + [ "text", " " ], + [ "keyword", "in" ], + [ "text", " " ], + [ "identifier", "p_data" ], + [ "text", " " ], + [ "keyword", "bytea" ], + [ "text", ", " ] + ] + }, + { + "state": "statement", + "data": [ + [ "text", " " ], + [ "keyword", "in" ], + [ "text", " " ], + [ "identifier", "p_chunk" ], + [ "text", " " ], + [ "keyword", "integer" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "dollarSql", + "data": [ + [ "keyword", "returns" ], + [ "text", " " ], + [ "keyword", "setof" ], + [ "text", " " ], + [ "keyword", "bytea" ], + [ "text", " " ], + [ "keyword", "as" ], + [ "text", " " ], + [ "string", "$$" ] + ] + }, + { + "state": "dollarSql", + "data": [ + [ "comment", "-- Still SQL comments" ] + ] + }, + { + "state": "dollarSql", + "data": [ + [ "keyword", "declare" ] + ] + }, + { + "state": "dollarSql", + "data": [ + [ "text", "\t" ], + [ "identifier", "v_size" ], + [ "text", " " ], + [ "keyword", "integer" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "support.function", "octet_length" ], + [ "paren.lparen", "(" ], + [ "identifier", "p_data" ], + [ "paren.rparen", ")" ], + [ "text", ";" ] + ] + }, + { + "state": "dollarSql", + "data": [ + [ "keyword", "begin" ] + ] + }, + { + "state": "dollarSql", + "data": [ + [ "text", "\t" ], + [ "keyword", "for" ], + [ "text", " " ], + [ "identifier", "i" ], + [ "text", " " ], + [ "keyword", "in" ], + [ "text", " " ], + [ "constant.numeric", "1" ], + [ "text", ".." ], + [ "identifier", "v_size" ], + [ "text", " " ], + [ "keyword", "by" ], + [ "text", " " ], + [ "identifier", "p_chunk" ], + [ "text", " " ], + [ "identifier", "loop" ] + ] + }, + { + "state": "dollarSql", + "data": [ + [ "text", "\t\t" ], + [ "identifier", "return" ], + [ "text", " " ], + [ "keyword", "next" ], + [ "text", " " ], + [ "keyword", "substring" ], + [ "paren.lparen", "(" ], + [ "identifier", "p_data" ], + [ "text", " " ], + [ "keyword", "from" ], + [ "text", " " ], + [ "identifier", "i" ], + [ "text", " " ], + [ "keyword", "for" ], + [ "text", " " ], + [ "identifier", "p_chunk" ], + [ "paren.rparen", ")" ], + [ "text", ";" ] + ] + }, + { + "state": "dollarSql", + "data": [ + [ "text", "\t" ], + [ "keyword", "end" ], + [ "text", " " ], + [ "identifier", "loop" ], + [ "text", ";" ] + ] + }, + { + "state": "dollarSql", + "data": [ + [ "keyword", "end" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "string", "$$" ], + [ "text", " " ], + [ "keyword", "language" ], + [ "text", " " ], + [ "identifier", "plpgsql" ], + [ "text", " " ], + [ "keyword", "stable" ], + [ "statementEnd", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "comment", "-- pl/perl" ] + ] + }, + { + "state": "perl-start", + "data": [ + [ "keyword.statementBegin", "CREATE" ], + [ "text", " " ], + [ "keyword", "FUNCTION" ], + [ "text", " " ], + [ "identifier", "perl_max" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "keyword", "integer" ], + [ "text", ", " ], + [ "keyword", "integer" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "keyword", "RETURNS" ], + [ "text", " " ], + [ "keyword", "integer" ], + [ "text", " " ], + [ "keyword", "AS" ], + [ "text", " " ], + [ "string", "$perl$" ] + ] + }, + { + "state": "perl-start", + "data": [ + [ "text", " " ], + [ "comment", "# perl comment..." ] + ] + }, + { + "state": "perl-start", + "data": [ + [ "text", " " ], + [ "keyword", "my" ], + [ "text", " " ], + [ "lparen", "(" ], + [ "identifier", "$x" ], + [ "keyword.operator", "," ], + [ "identifier", "$y" ], + [ "rparen", ")" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " @" ], + [ "identifier", "_" ], + [ "text", ";" ] + ] + }, + { + "state": "perl-start", + "data": [ + [ "text", " " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "lparen", "(" ], + [ "keyword.operator", "!" ], + [ "text", " " ], + [ "support.function", "defined" ], + [ "text", " " ], + [ "identifier", "$x" ], + [ "rparen", ")" ], + [ "text", " " ], + [ "lparen", "{" ] + ] + }, + { + "state": "perl-start", + "data": [ + [ "text", " " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "lparen", "(" ], + [ "keyword.operator", "!" ], + [ "text", " " ], + [ "support.function", "defined" ], + [ "text", " " ], + [ "identifier", "$y" ], + [ "rparen", ")" ], + [ "text", " " ], + [ "lparen", "{" ], + [ "text", " " ], + [ "support.function", "return" ], + [ "text", " " ], + [ "support.function", "undef" ], + [ "text", "; " ], + [ "rparen", "}" ] + ] + }, + { + "state": "perl-start", + "data": [ + [ "text", " " ], + [ "support.function", "return" ], + [ "text", " " ], + [ "identifier", "$y" ], + [ "text", ";" ] + ] + }, + { + "state": "perl-start", + "data": [ + [ "text", " " ], + [ "rparen", "}" ] + ] + }, + { + "state": "perl-start", + "data": [ + [ "text", " " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "lparen", "(" ], + [ "keyword.operator", "!" ], + [ "text", " " ], + [ "support.function", "defined" ], + [ "text", " " ], + [ "identifier", "$y" ], + [ "rparen", ")" ], + [ "text", " " ], + [ "lparen", "{" ], + [ "text", " " ], + [ "support.function", "return" ], + [ "text", " " ], + [ "identifier", "$x" ], + [ "text", "; " ], + [ "rparen", "}" ] + ] + }, + { + "state": "perl-start", + "data": [ + [ "text", " " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "lparen", "(" ], + [ "identifier", "$x" ], + [ "text", " " ], + [ "keyword.operator", ">" ], + [ "text", " " ], + [ "identifier", "$y" ], + [ "rparen", ")" ], + [ "text", " " ], + [ "lparen", "{" ], + [ "text", " " ], + [ "support.function", "return" ], + [ "text", " " ], + [ "identifier", "$x" ], + [ "text", "; " ], + [ "rparen", "}" ] + ] + }, + { + "state": "perl-start", + "data": [ + [ "text", " " ], + [ "support.function", "return" ], + [ "text", " " ], + [ "identifier", "$y" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "string", "$perl$" ], + [ "text", " " ], + [ "keyword", "LANGUAGE" ], + [ "text", " " ], + [ "identifier", "plperl" ], + [ "statementEnd", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "comment", "-- pl/python" ] + ] + }, + { + "state": "python-start", + "data": [ + [ "keyword.statementBegin", "CREATE" ], + [ "text", " " ], + [ "keyword", "FUNCTION" ], + [ "text", " " ], + [ "identifier", "usesavedplan" ], + [ "paren.lparen", "(" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "keyword", "RETURNS" ], + [ "text", " " ], + [ "keyword", "trigger" ], + [ "text", " " ], + [ "keyword", "AS" ], + [ "text", " " ], + [ "string", "$python$" ] + ] + }, + { + "state": "python-start", + "data": [ + [ "text", " " ], + [ "comment", "# python comment..." ] + ] + }, + { + "state": "python-start", + "data": [ + [ "text", " " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "identifier", "SD" ], + [ "text", "." ], + [ "identifier", "has_key" ], + [ "paren.lparen", "(" ], + [ "string", "\"plan\"" ], + [ "paren.rparen", ")" ], + [ "text", ":" ] + ] + }, + { + "state": "python-start", + "data": [ + [ "text", " " ], + [ "identifier", "plan" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "identifier", "SD" ], + [ "paren.lparen", "[" ], + [ "string", "\"plan\"" ], + [ "paren.rparen", "]" ] + ] + }, + { + "state": "python-start", + "data": [ + [ "text", " " ], + [ "keyword", "else" ], + [ "text", ":" ] + ] + }, + { + "state": "python-start", + "data": [ + [ "text", " " ], + [ "identifier", "plan" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "identifier", "plpy" ], + [ "text", "." ], + [ "identifier", "prepare" ], + [ "paren.lparen", "(" ], + [ "string", "\"SELECT 1\"" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "python-start", + "data": [ + [ "text", " " ], + [ "identifier", "SD" ], + [ "paren.lparen", "[" ], + [ "string", "\"plan\"" ], + [ "paren.rparen", "]" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "identifier", "plan" ] + ] + }, + { + "state": "start", + "data": [ + [ "string", "$python$" ], + [ "text", " " ], + [ "keyword", "LANGUAGE" ], + [ "text", " " ], + [ "identifier", "plpythonu" ], + [ "statementEnd", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "comment", "-- psql commands" ] + ] + }, + { + "state": "start", + "data": [ + [ "support.buildin", "\\df cash*" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "comment", "-- Some string samples." ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword.statementBegin", "select" ], + [ "text", " " ], + [ "string", "'don'" ], + [ "string", "'t do it now;'" ], + [ "text", " " ], + [ "keyword.operator", "|" ], + [ "keyword.operator", "|" ], + [ "text", " " ], + [ "string", "'maybe later'" ], + [ "statementEnd", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword.statementBegin", "select" ], + [ "text", " " ], + [ "identifier", "E" ], + [ "string", "'dont\\'t do it'" ], + [ "statementEnd", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword.statementBegin", "select" ], + [ "text", " " ], + [ "support.function", "length" ], + [ "paren.lparen", "(" ], + [ "string", "'some other'" ], + [ "string", "'s stuff'" ], + [ "text", " " ], + [ "keyword.operator", "|" ], + [ "keyword.operator", "|" ], + [ "text", " " ], + [ "string", "$$" ], + [ "string", "cat in hat's stuff $$" ], + [ "paren.rparen", ")" ], + [ "statementEnd", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "dollarStatementString", + "data": [ + [ "keyword.statementBegin", "select" ], + [ "text", " " ], + [ "string", "$$ strings" ] + ] + }, + { + "state": "dollarStatementString", + "data": [ + [ "string", "over multiple " ] + ] + }, + { + "state": "dollarStatementString", + "data": [ + [ "string", "lines - use dollar quotes" ] + ] + }, + { + "state": "start", + "data": [ + [ "string", "$$" ], + [ "statementEnd", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword.statementBegin", "END" ], + [ "statementEnd", ";" ] + ] + }, + { + "state": "start", + "data": [] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_php.json b/lib/ace/mode/_test/tokens_php.json new file mode 100644 index 0000000000..4af8737561 --- /dev/null +++ b/lib/ace/mode/_test/tokens_php.json @@ -0,0 +1,238 @@ +[ + { + "state": "php-start", + "data": [ + [ "support.php_tag", "" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_powershell.json b/lib/ace/mode/_test/tokens_powershell.json new file mode 100644 index 0000000000..d2fa444e98 --- /dev/null +++ b/lib/ace/mode/_test/tokens_powershell.json @@ -0,0 +1,255 @@ +[ + { + "state": "start", + "data": [ + [ "comment", "# This is a simple comment" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "function" ], + [ "text", " " ], + [ "identifier", "Hello" ], + [ "lparen", "(" ], + [ "variable.instance", "$name" ], + [ "rparen", ")" ], + [ "text", " " ], + [ "lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "Write-host" ], + [ "text", " " ], + [ "string", "\"Hello $name\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "function" ], + [ "text", " " ], + [ "identifier", "add" ], + [ "lparen", "(" ], + [ "variable.instance", "$left" ], + [ "text", ", " ], + [ "variable.instance", "$right" ], + [ "keyword.operator", "=" ], + [ "constant.numeric", "4" ], + [ "rparen", ")" ], + [ "text", " " ], + [ "lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "lparen", "(" ], + [ "variable.instance", "$right" ], + [ "text", " " ], + [ "keyword.operator", "-ne" ], + [ "text", " " ], + [ "constant.numeric", "4" ], + [ "rparen", ")" ], + [ "text", " " ], + [ "lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "return" ], + [ "text", " " ], + [ "variable.instance", "$left" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "rparen", "}" ], + [ "text", " " ], + [ "keyword", "elseif" ], + [ "text", " " ], + [ "lparen", "(" ], + [ "variable.instance", "$left" ], + [ "text", " " ], + [ "keyword.operator", "-eq" ], + [ "text", " " ], + [ "constant.language", "$null" ], + [ "text", " " ], + [ "keyword.operator", "-and" ], + [ "text", " " ], + [ "variable.instance", "$right" ], + [ "text", " " ], + [ "keyword.operator", "-eq" ], + [ "text", " " ], + [ "constant.numeric", "2" ], + [ "rparen", ")" ], + [ "text", " " ], + [ "lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "return" ], + [ "text", " " ], + [ "constant.numeric", "3" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "rparen", "}" ], + [ "text", " " ], + [ "keyword", "else" ], + [ "text", " " ], + [ "lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "return" ], + [ "text", " " ], + [ "constant.numeric", "2" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "variable.instance", "$number" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "constant.numeric", "1" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "text", " " ], + [ "constant.numeric", "2" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "variable.instance", "$number" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "constant.numeric", "3" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.function", "Write-Host" ], + [ "text", " " ], + [ "identifier", "Hello" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "identifier", "name" ], + [ "text", " " ], + [ "string", "\"World\"" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "variable.instance", "$an_array" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " @" ], + [ "lparen", "(" ], + [ "constant.numeric", "1" ], + [ "text", ", " ], + [ "constant.numeric", "2" ], + [ "text", ", " ], + [ "constant.numeric", "3" ], + [ "rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "variable.instance", "$a_hash" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " @" ], + [ "lparen", "{" ], + [ "string", "\"something\"" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "string", "\"something else\"" ], + [ "rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword.operator", "&" ], + [ "text", " " ], + [ "identifier", "notepad" ], + [ "text", " .\\" ], + [ "identifier", "readme" ], + [ "text", "." ], + [ "identifier", "md" ] + ] + }, + { + "state": "start", + "data": [] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_python.json b/lib/ace/mode/_test/tokens_python.json new file mode 100644 index 0000000000..5936fce225 --- /dev/null +++ b/lib/ace/mode/_test/tokens_python.json @@ -0,0 +1,205 @@ +[ + { + "state": "start", + "data": [ + [ "comment", "#!/usr/local/bin/python" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "import" ], + [ "text", " " ], + [ "identifier", "string" ], + [ "text", ", " ], + [ "identifier", "sys" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "comment", "# If no arguments were given, print a helpful message" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "if" ], + [ "text", " " ], + [ "support.function", "len" ], + [ "paren.lparen", "(" ], + [ "identifier", "sys" ], + [ "text", "." ], + [ "identifier", "argv" ], + [ "paren.rparen", ")" ], + [ "keyword.operator", "==" ], + [ "constant.numeric", "1" ], + [ "text", ":" ] + ] + }, + { + "state": "qstring", + "data": [ + [ "text", " " ], + [ "keyword", "print" ], + [ "text", " " ], + [ "string", "'''Usage:" ] + ] + }, + { + "state": "start", + "data": [ + [ "string", "celsius temp1 temp2 ...'''" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "sys" ], + [ "text", "." ], + [ "identifier", "exit" ], + [ "paren.lparen", "(" ], + [ "constant.numeric", "0" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "comment", "# Loop over the arguments" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "for" ], + [ "text", " " ], + [ "identifier", "i" ], + [ "text", " " ], + [ "keyword", "in" ], + [ "text", " " ], + [ "identifier", "sys" ], + [ "text", "." ], + [ "identifier", "argv" ], + [ "paren.lparen", "[" ], + [ "constant.numeric", "1" ], + [ "text", ":" ], + [ "paren.rparen", "]" ], + [ "text", ":" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "try" ], + [ "text", ":" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "fahrenheit" ], + [ "keyword.operator", "=" ], + [ "support.function", "float" ], + [ "paren.lparen", "(" ], + [ "identifier", "string" ], + [ "text", "." ], + [ "identifier", "atoi" ], + [ "paren.lparen", "(" ], + [ "identifier", "i" ], + [ "paren.rparen", ")" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "except" ], + [ "text", " " ], + [ "identifier", "string" ], + [ "text", "." ], + [ "identifier", "atoi_error" ], + [ "text", ":" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "print" ], + [ "text", " " ], + [ "support.function", "repr" ], + [ "paren.lparen", "(" ], + [ "identifier", "i" ], + [ "paren.rparen", ")" ], + [ "text", ", " ], + [ "string", "\"not a numeric value\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "else" ], + [ "text", ":" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "celsius" ], + [ "keyword.operator", "=" ], + [ "paren.lparen", "(" ], + [ "identifier", "fahrenheit" ], + [ "keyword.operator", "-" ], + [ "constant.numeric", "32" ], + [ "paren.rparen", ")" ], + [ "keyword.operator", "*" ], + [ "constant.numeric", "5.0" ], + [ "keyword.operator", "/" ], + [ "constant.numeric", "9.0" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "print" ], + [ "text", " " ], + [ "string", "'%i\\260F = %i\\260C'" ], + [ "text", " " ], + [ "keyword.operator", "%" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "support.function", "int" ], + [ "paren.lparen", "(" ], + [ "identifier", "fahrenheit" ], + [ "paren.rparen", ")" ], + [ "text", ", " ], + [ "support.function", "int" ], + [ "paren.lparen", "(" ], + [ "identifier", "celsius" ], + [ "keyword.operator", "+" ], + [ "constant.numeric", ".5" ], + [ "paren.rparen", ")" ], + [ "paren.rparen", ")" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_ruby.json b/lib/ace/mode/_test/tokens_ruby.json new file mode 100644 index 0000000000..02160407e4 --- /dev/null +++ b/lib/ace/mode/_test/tokens_ruby.json @@ -0,0 +1,104 @@ +[ + { + "state": "start", + "data": [ + [ "comment", "#!/usr/bin/ruby" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "comment", "# Program to find the factorial of a number" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "def" ], + [ "text", " " ], + [ "identifier", "fact" ], + [ "paren.lparen", "(" ], + [ "identifier", "n" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "identifier", "n" ], + [ "text", " " ], + [ "keyword.operator", "==" ], + [ "text", " " ], + [ "constant.numeric", "0" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "constant.numeric", "1" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "else" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "n" ], + [ "text", " " ], + [ "keyword.operator", "*" ], + [ "text", " " ], + [ "identifier", "fact" ], + [ "paren.lparen", "(" ], + [ "identifier", "n" ], + [ "constant.numeric", "-1" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "end" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "end" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.function", "puts" ], + [ "text", " " ], + [ "identifier", "fact" ], + [ "paren.lparen", "(" ], + [ "variable.class", "ARGV" ], + [ "paren.lparen", "[" ], + [ "constant.numeric", "0" ], + [ "paren.rparen", "]" ], + [ "text", "." ], + [ "identifier", "to_i" ], + [ "paren.rparen", ")" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_scad.json b/lib/ace/mode/_test/tokens_scad.json new file mode 100644 index 0000000000..b9eefe5f2b --- /dev/null +++ b/lib/ace/mode/_test/tokens_scad.json @@ -0,0 +1,267 @@ +[ + { + "state": "start", + "data": [ + [ "comment", "// ace can highlight scad!" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "module" ], + [ "text", " " ], + [ "identifier", "Element" ], + [ "paren.lparen", "(" ], + [ "identifier", "xpos" ], + [ "text", ", " ], + [ "identifier", "ypos" ], + [ "text", ", " ], + [ "identifier", "zpos" ], + [ "paren.rparen", ")" ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "identifier", "translate" ], + [ "paren.lparen", "(" ], + [ "paren.lparen", "[" ], + [ "identifier", "xpos" ], + [ "text", "," ], + [ "identifier", "ypos" ], + [ "text", "," ], + [ "identifier", "zpos" ], + [ "paren.rparen", "]" ], + [ "paren.rparen", ")" ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t\t" ], + [ "identifier", "union" ], + [ "paren.lparen", "(" ], + [ "paren.rparen", ")" ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t\t\t" ], + [ "identifier", "cube" ], + [ "paren.lparen", "(" ], + [ "paren.lparen", "[" ], + [ "constant.numeric", "10" ], + [ "text", "," ], + [ "constant.numeric", "10" ], + [ "text", "," ], + [ "constant.numeric", "4" ], + [ "paren.rparen", "]" ], + [ "text", "," ], + [ "identifier", "true" ], + [ "paren.rparen", ")" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t\t\t" ], + [ "identifier", "cylinder" ], + [ "paren.lparen", "(" ], + [ "constant.numeric", "10" ], + [ "text", "," ], + [ "constant.numeric", "15" ], + [ "text", "," ], + [ "constant.numeric", "5" ], + [ "paren.rparen", ")" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t\t\t" ], + [ "identifier", "translate" ], + [ "paren.lparen", "(" ], + [ "paren.lparen", "[" ], + [ "constant.numeric", "0" ], + [ "text", "," ], + [ "constant.numeric", "0" ], + [ "text", "," ], + [ "constant.numeric", "10" ], + [ "paren.rparen", "]" ], + [ "paren.rparen", ")" ], + [ "identifier", "sphere" ], + [ "paren.lparen", "(" ], + [ "constant.numeric", "5" ], + [ "paren.rparen", ")" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t\t" ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "identifier", "union" ], + [ "paren.lparen", "(" ], + [ "paren.rparen", ")" ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "keyword", "for" ], + [ "paren.lparen", "(" ], + [ "identifier", "i" ], + [ "keyword.operator", "=" ], + [ "paren.lparen", "[" ], + [ "constant.numeric", "0" ], + [ "text", ":" ], + [ "constant.numeric", "30" ], + [ "paren.rparen", "]" ], + [ "paren.rparen", ")" ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t\t# " ], + [ "identifier", "Element" ], + [ "paren.lparen", "(" ], + [ "constant.numeric", "0" ], + [ "text", "," ], + [ "constant.numeric", "0" ], + [ "text", "," ], + [ "constant.numeric", "0" ], + [ "paren.rparen", ")" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t\t" ], + [ "identifier", "Element" ], + [ "paren.lparen", "(" ], + [ "constant.numeric", "15" ], + [ "keyword.operator", "*" ], + [ "identifier", "i" ], + [ "text", "," ], + [ "constant.numeric", "0" ], + [ "text", "," ], + [ "constant.numeric", "0" ], + [ "paren.rparen", ")" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "for" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "identifier", "i" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "paren.lparen", "[" ], + [ "constant.numeric", "3" ], + [ "text", ", " ], + [ "constant.numeric", "5" ], + [ "text", ", " ], + [ "constant.numeric", "7" ], + [ "text", ", " ], + [ "constant.numeric", "11" ], + [ "paren.rparen", "]" ], + [ "paren.rparen", ")" ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "identifier", "rotate" ], + [ "paren.lparen", "(" ], + [ "paren.lparen", "[" ], + [ "identifier", "i" ], + [ "keyword.operator", "*" ], + [ "constant.numeric", "10" ], + [ "text", "," ], + [ "constant.numeric", "0" ], + [ "text", "," ], + [ "constant.numeric", "0" ], + [ "paren.rparen", "]" ], + [ "paren.rparen", ")" ], + [ "identifier", "scale" ], + [ "paren.lparen", "(" ], + [ "paren.lparen", "[" ], + [ "constant.numeric", "1" ], + [ "text", "," ], + [ "constant.numeric", "1" ], + [ "text", "," ], + [ "identifier", "i" ], + [ "paren.rparen", "]" ], + [ "paren.rparen", ")" ], + [ "identifier", "cube" ], + [ "paren.lparen", "(" ], + [ "constant.numeric", "10" ], + [ "paren.rparen", ")" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_scala.json b/lib/ace/mode/_test/tokens_scala.json new file mode 100644 index 0000000000..88fa833273 --- /dev/null +++ b/lib/ace/mode/_test/tokens_scala.json @@ -0,0 +1,748 @@ +[ + { + "state": "start", + "data": [ + [ "comment", "// http://www.scala-lang.org/node/54" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "package" ], + [ "text", " " ], + [ "identifier", "examples" ], + [ "text", "." ], + [ "identifier", "actors" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "import" ], + [ "text", " " ], + [ "identifier", "scala" ], + [ "text", "." ], + [ "identifier", "actors" ], + [ "text", "." ], + [ "identifier", "Actor" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "import" ], + [ "text", " " ], + [ "identifier", "scala" ], + [ "text", "." ], + [ "identifier", "actors" ], + [ "text", "." ], + [ "identifier", "Actor" ], + [ "text", "." ], + [ "identifier", "_" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "abstract" ], + [ "text", " " ], + [ "keyword", "class" ], + [ "text", " " ], + [ "identifier", "PingMessage" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "case" ], + [ "text", " " ], + [ "keyword", "object" ], + [ "text", " " ], + [ "identifier", "Start" ], + [ "text", " " ], + [ "keyword", "extends" ], + [ "text", " " ], + [ "identifier", "PingMessage" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "case" ], + [ "text", " " ], + [ "keyword", "object" ], + [ "text", " " ], + [ "identifier", "SendPing" ], + [ "text", " " ], + [ "keyword", "extends" ], + [ "text", " " ], + [ "identifier", "PingMessage" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "case" ], + [ "text", " " ], + [ "keyword", "object" ], + [ "text", " " ], + [ "identifier", "Pong" ], + [ "text", " " ], + [ "keyword", "extends" ], + [ "text", " " ], + [ "identifier", "PingMessage" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "abstract" ], + [ "text", " " ], + [ "keyword", "class" ], + [ "text", " " ], + [ "identifier", "PongMessage" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "case" ], + [ "text", " " ], + [ "keyword", "object" ], + [ "text", " " ], + [ "identifier", "Ping" ], + [ "text", " " ], + [ "keyword", "extends" ], + [ "text", " " ], + [ "identifier", "PongMessage" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "case" ], + [ "text", " " ], + [ "keyword", "object" ], + [ "text", " " ], + [ "identifier", "Stop" ], + [ "text", " " ], + [ "keyword", "extends" ], + [ "text", " " ], + [ "identifier", "PongMessage" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "object" ], + [ "text", " " ], + [ "identifier", "pingpong" ], + [ "text", " " ], + [ "keyword", "extends" ], + [ "text", " " ], + [ "identifier", "Application" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "val" ], + [ "text", " " ], + [ "identifier", "pong" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "keyword", "new" ], + [ "text", " " ], + [ "identifier", "Pong" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "val" ], + [ "text", " " ], + [ "identifier", "ping" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "keyword", "new" ], + [ "text", " " ], + [ "identifier", "Ping" ], + [ "paren.lparen", "(" ], + [ "constant.numeric", "100000" ], + [ "text", ", " ], + [ "identifier", "pong" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "ping" ], + [ "text", "." ], + [ "identifier", "start" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "pong" ], + [ "text", "." ], + [ "identifier", "start" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "ping" ], + [ "text", " " ], + [ "keyword.operator", "!" ], + [ "text", " " ], + [ "identifier", "Start" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "class" ], + [ "text", " " ], + [ "identifier", "Ping" ], + [ "paren.lparen", "(" ], + [ "identifier", "count" ], + [ "text", ": " ], + [ "support.function", "Int" ], + [ "text", ", " ], + [ "identifier", "pong" ], + [ "text", ": " ], + [ "identifier", "Actor" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "keyword", "extends" ], + [ "text", " " ], + [ "identifier", "Actor" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "def" ], + [ "text", " " ], + [ "identifier", "act" ], + [ "paren.lparen", "(" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "println" ], + [ "paren.lparen", "(" ], + [ "string", "\"Ping: Initializing with count \"" ], + [ "keyword.operator", "+" ], + [ "identifier", "count" ], + [ "keyword.operator", "+" ], + [ "string", "\": \"" ], + [ "keyword.operator", "+" ], + [ "identifier", "pong" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "var" ], + [ "text", " " ], + [ "identifier", "pingsLeft" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "identifier", "count" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "loop" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "react" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "case" ], + [ "text", " " ], + [ "identifier", "Start" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "keyword.operator", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "println" ], + [ "paren.lparen", "(" ], + [ "string", "\"Ping: starting.\"" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "pong" ], + [ "text", " " ], + [ "keyword.operator", "!" ], + [ "text", " " ], + [ "identifier", "Ping" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "pingsLeft" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "identifier", "pingsLeft" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "text", " " ], + [ "constant.numeric", "1" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "case" ], + [ "text", " " ], + [ "identifier", "SendPing" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "keyword.operator", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "pong" ], + [ "text", " " ], + [ "keyword.operator", "!" ], + [ "text", " " ], + [ "identifier", "Ping" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "pingsLeft" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "identifier", "pingsLeft" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "text", " " ], + [ "constant.numeric", "1" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "case" ], + [ "text", " " ], + [ "identifier", "Pong" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "keyword.operator", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "identifier", "pingsLeft" ], + [ "text", " " ], + [ "keyword.operator", "%" ], + [ "text", " " ], + [ "constant.numeric", "1000" ], + [ "text", " " ], + [ "keyword.operator", "==" ], + [ "text", " " ], + [ "constant.numeric", "0" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "println" ], + [ "paren.lparen", "(" ], + [ "string", "\"Ping: pong from: \"" ], + [ "keyword.operator", "+" ], + [ "identifier", "sender" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "identifier", "pingsLeft" ], + [ "text", " " ], + [ "keyword.operator", ">" ], + [ "text", " " ], + [ "constant.numeric", "0" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "self" ], + [ "text", " " ], + [ "keyword.operator", "!" ], + [ "text", " " ], + [ "identifier", "SendPing" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "else" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "println" ], + [ "paren.lparen", "(" ], + [ "string", "\"Ping: Stop.\"" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "pong" ], + [ "text", " " ], + [ "keyword.operator", "!" ], + [ "text", " " ], + [ "identifier", "Stop" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "exit" ], + [ "paren.lparen", "(" ], + [ "symbol.constant", "'stop" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "class" ], + [ "text", " " ], + [ "identifier", "Pong" ], + [ "text", " " ], + [ "keyword", "extends" ], + [ "text", " " ], + [ "identifier", "Actor" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "def" ], + [ "text", " " ], + [ "identifier", "act" ], + [ "paren.lparen", "(" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "var" ], + [ "text", " " ], + [ "identifier", "pongCount" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "constant.numeric", "0" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "loop" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "react" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "case" ], + [ "text", " " ], + [ "identifier", "Ping" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "keyword.operator", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "identifier", "pongCount" ], + [ "text", " " ], + [ "keyword.operator", "%" ], + [ "text", " " ], + [ "constant.numeric", "1000" ], + [ "text", " " ], + [ "keyword.operator", "==" ], + [ "text", " " ], + [ "constant.numeric", "0" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "println" ], + [ "paren.lparen", "(" ], + [ "string", "\"Pong: ping \"" ], + [ "keyword.operator", "+" ], + [ "identifier", "pongCount" ], + [ "keyword.operator", "+" ], + [ "string", "\" from \"" ], + [ "keyword.operator", "+" ], + [ "identifier", "sender" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "sender" ], + [ "text", " " ], + [ "keyword.operator", "!" ], + [ "text", " " ], + [ "identifier", "Pong" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "pongCount" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "identifier", "pongCount" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "text", " " ], + [ "constant.numeric", "1" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "case" ], + [ "text", " " ], + [ "identifier", "Stop" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "keyword.operator", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "println" ], + [ "paren.lparen", "(" ], + [ "string", "\"Pong: Stop.\"" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "exit" ], + [ "paren.lparen", "(" ], + [ "symbol.constant", "'stop" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_scss.json b/lib/ace/mode/_test/tokens_scss.json new file mode 100644 index 0000000000..fddaeda526 --- /dev/null +++ b/lib/ace/mode/_test/tokens_scss.json @@ -0,0 +1,181 @@ +[ + { + "state": "start", + "data": [ + [ "comment", "/*" ], + [ "comment", " style.scss */" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "variable.language", "#navbar" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "$navbar-width" ], + [ "text", ": " ], + [ "constant.numeric", "800px" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "$items" ], + [ "text", ": " ], + [ "constant.numeric", "5" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "$navbar-color" ], + [ "text", ": " ], + [ "constant.numeric", "#ce4dd6" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "support.type", "width" ], + [ "text", ": " ], + [ "variable", "$navbar-width" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "support.type", "border-bottom" ], + [ "text", ": " ], + [ "constant.numeric", "2px" ], + [ "text", " " ], + [ "constant.language", "solid" ], + [ "text", " " ], + [ "variable", "$navbar-color" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable.language", "li" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "support.type", "float" ], + [ "text", ": " ], + [ "support.type", "left" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "support.type", "width" ], + [ "text", ": " ], + [ "variable", "$navbar-width" ], + [ "text", "/" ], + [ "variable", "$items" ], + [ "text", " " ], + [ "constant", "-" ], + [ "text", " " ], + [ "constant.numeric", "10px" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "support.type", "background-color" ], + [ "text", ": " ], + [ "support.function", "lighten" ], + [ "paren.lparen", "(" ], + [ "variable", "$navbar-color" ], + [ "text", ", " ], + [ "constant.numeric", "20%" ], + [ "paren.rparen", ")" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " &" ], + [ "variable.language", ":hover" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "support.type", "background-color" ], + [ "text", ": " ], + [ "support.function", "lighten" ], + [ "paren.lparen", "(" ], + [ "variable", "$navbar-color" ], + [ "text", ", " ], + [ "constant.numeric", "10%" ], + [ "paren.rparen", ")" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_sh.json b/lib/ace/mode/_test/tokens_sh.json new file mode 100644 index 0000000000..582282fb32 --- /dev/null +++ b/lib/ace/mode/_test/tokens_sh.json @@ -0,0 +1,434 @@ +[ + { + "state": "start", + "data": [ + [ "comment", "#!/bin/sh" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "comment", "# Script to open a browser to current branch" ] + ] + }, + { + "state": "start", + "data": [ + [ "comment", "# Repo formats:" ] + ] + }, + { + "state": "start", + "data": [ + [ "comment", "# ssh git@github.com:richoH/gh_pr.git" ] + ] + }, + { + "state": "start", + "data": [ + [ "comment", "# http https://richoH@github.com/richoH/gh_pr.git" ] + ] + }, + { + "state": "start", + "data": [ + [ "comment", "# git git://github.com/richoH/gh_pr.git" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "variable", "username=" ], + [ "text", "`" ], + [ "identifier", "git" ], + [ "text", " " ], + [ "identifier", "config" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "keyword.operator", "-" ], + [ "identifier", "get" ], + [ "text", " " ], + [ "identifier", "github" ], + [ "text", "." ], + [ "identifier", "user" ], + [ "text", "`" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "support.function", "get_repo()" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "git" ], + [ "text", " " ], + [ "identifier", "remote" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "identifier", "v" ], + [ "text", " | " ], + [ "identifier", "grep" ], + [ "text", " $" ], + [ "paren.lparen", "{" ], + [ "text", "@:" ], + [ "keyword.operator", "-" ], + [ "variable", "$username" ], + [ "paren.rparen", "}" ], + [ "text", " | " ], + [ "keyword", "while" ], + [ "text", " " ], + [ "keyword", "read" ], + [ "text", " " ], + [ "identifier", "remote" ], + [ "text", "; " ], + [ "keyword", "do" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "variable", "repo=" ], + [ "text", "`" ], + [ "constant.language", "echo" ], + [ "text", " " ], + [ "variable", "$remote" ], + [ "text", " | " ], + [ "identifier", "grep" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "identifier", "E" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "identifier", "o" ], + [ "text", " " ], + [ "string", "\"git@github.com:[^ ]*\"" ], + [ "text", "`; " ], + [ "keyword", "then" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "constant.language", "echo" ], + [ "text", " " ], + [ "variable", "$repo" ], + [ "text", " | " ], + [ "identifier", "sed" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "identifier", "e" ], + [ "text", " " ], + [ "string", "\"s/^git@github\\.com://\"" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "identifier", "e" ], + [ "text", " " ], + [ "string", "\"s/\\.git$//\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "constant.language", "exit" ], + [ "text", " " ], + [ "constant.numeric", "1" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "fi" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "variable", "repo=" ], + [ "text", "`" ], + [ "constant.language", "echo" ], + [ "text", " " ], + [ "variable", "$remote" ], + [ "text", " | " ], + [ "identifier", "grep" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "identifier", "E" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "identifier", "o" ], + [ "text", " " ], + [ "string", "\"https?://([^@]*@)?github.com/[^ ]*\\.git\"" ], + [ "text", "`; " ], + [ "keyword", "then" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "constant.language", "echo" ], + [ "text", " " ], + [ "variable", "$repo" ], + [ "text", " | " ], + [ "identifier", "sed" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "identifier", "e" ], + [ "text", " " ], + [ "string", "\"s|^https?://||\"" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "identifier", "e" ], + [ "text", " " ], + [ "string", "\"s/^.*github\\.com\\///\"" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "identifier", "e" ], + [ "text", " " ], + [ "string", "\"s/\\.git$//\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "constant.language", "exit" ], + [ "text", " " ], + [ "constant.numeric", "1" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "fi" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "variable", "repo=" ], + [ "text", "`" ], + [ "constant.language", "echo" ], + [ "text", " " ], + [ "variable", "$remote" ], + [ "text", " | " ], + [ "identifier", "grep" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "identifier", "E" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "identifier", "o" ], + [ "text", " " ], + [ "string", "\"git://github.com/[^ ]*\\.git\"" ], + [ "text", "`; " ], + [ "keyword", "then" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "constant.language", "echo" ], + [ "text", " " ], + [ "variable", "$repo" ], + [ "text", " | " ], + [ "identifier", "sed" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "identifier", "e" ], + [ "text", " " ], + [ "string", "\"s|^git://github.com/||\"" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "identifier", "e" ], + [ "text", " " ], + [ "string", "\"s/\\.git$//\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "constant.language", "exit" ], + [ "text", " " ], + [ "constant.numeric", "1" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "fi" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "done" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "paren.lparen", "[" ], + [ "text", " " ], + [ "variable.language", "$?" ], + [ "text", " " ], + [ "keyword.operator", "-" ], + [ "identifier", "eq" ], + [ "text", " " ], + [ "constant.numeric", "0" ], + [ "text", " " ], + [ "paren.rparen", "]" ], + [ "text", "; " ], + [ "keyword", "then" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "constant.language", "echo" ], + [ "text", " " ], + [ "string", "\"Couldn't find a valid remote\"" ], + [ "text", " " ], + [ "keyword.operator", ">" ], + [ "support.function", "&2" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "constant.language", "exit" ], + [ "text", " " ], + [ "constant.numeric", "1" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "fi" ] + ] + }, + { + "state": "start", + "data": [ + [ "paren.rparen", "}" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "if" ], + [ "text", " " ], + [ "variable", "repo=" ], + [ "text", "`" ], + [ "identifier", "get_repo" ], + [ "text", " $@`; " ], + [ "keyword", "then" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "variable", "branch=" ], + [ "text", "`" ], + [ "identifier", "git" ], + [ "text", " " ], + [ "identifier", "symbolic" ], + [ "keyword.operator", "-" ], + [ "identifier", "ref" ], + [ "text", " " ], + [ "identifier", "HEAD" ], + [ "text", " " ], + [ "constant.numeric", "2" ], + [ "keyword.operator", ">" ], + [ "keyword.operator", "/" ], + [ "identifier", "dev" ], + [ "keyword.operator", "/" ], + [ "identifier", "null" ], + [ "text", "`" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "constant.language", "echo" ], + [ "text", " " ], + [ "string", "\"http://github.com/$repo/pull/new/${branch##refs/heads/}\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "else" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "constant.language", "exit" ], + [ "text", " " ], + [ "constant.numeric", "1" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "fi" ] + ] + }, + { + "state": "start", + "data": [] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_sql.json b/lib/ace/mode/_test/tokens_sql.json new file mode 100644 index 0000000000..525af9d43c --- /dev/null +++ b/lib/ace/mode/_test/tokens_sql.json @@ -0,0 +1,73 @@ +[ + { + "state": "start", + "data": [ + [ "keyword", "SELECT" ], + [ "text", " " ], + [ "identifier", "city" ], + [ "text", ", " ], + [ "support.function", "COUNT" ], + [ "paren.lparen", "(" ], + [ "identifier", "id" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "keyword", "AS" ], + [ "text", " " ], + [ "identifier", "users_count" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "FROM" ], + [ "text", " " ], + [ "identifier", "users" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "WHERE" ], + [ "text", " " ], + [ "identifier", "group_name" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "string", "'salesman'" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "AND" ], + [ "text", " " ], + [ "identifier", "created" ], + [ "text", " " ], + [ "keyword.operator", ">" ], + [ "text", " " ], + [ "string", "'2011-05-21'" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "GROUP" ], + [ "text", " " ], + [ "keyword", "BY" ], + [ "text", " " ], + [ "constant.numeric", "1" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "ORDER" ], + [ "text", " " ], + [ "keyword", "BY" ], + [ "text", " " ], + [ "constant.numeric", "2" ], + [ "text", " " ], + [ "keyword", "DESC" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_svg.json b/lib/ace/mode/_test/tokens_svg.json new file mode 100644 index 0000000000..ed1beb9bdb --- /dev/null +++ b/lib/ace/mode/_test/tokens_svg.json @@ -0,0 +1,931 @@ +[ + { + "state": "tag_embed_attribute_list", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "svg" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "width" ], + [ "keyword.operator", "=" ], + [ "string", "\"800\"" ], + [ "text", " " ], + [ "entity.other.attribute-name", "height" ], + [ "keyword.operator", "=" ], + [ "string", "\"600\"" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "xmlns" ], + [ "keyword.operator", "=" ], + [ "string", "\"http://www.w3.org/2000/svg\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "onload" ], + [ "keyword.operator", "=" ], + [ "string", "\"StartAnimation(evt)\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "title" ], + [ "meta.tag", ">" ], + [ "text", "Test Tube Progress Bar" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "desc" ], + [ "meta.tag", ">" ], + [ "text", "Created for the Web Directions SVG competition" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "script" ], + [ "text", " " ], + [ "entity.other.attribute-name", "type" ], + [ "keyword.operator", "=" ], + [ "string", "\"text/ecmascript\"" ], + [ "meta.tag", ">" ], + [ "keyword.operator", "<" ], + [ "keyword.operator", "!" ], + [ "paren.lparen", "[" ], + [ "identifier", "CDATA" ], + [ "paren.lparen", "[" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "storage.type", "var" ], + [ "text", " " ], + [ "identifier", "timevalue" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "constant.numeric", "0" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "storage.type", "var" ], + [ "text", " " ], + [ "identifier", "timer_increment" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "constant.numeric", "1" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "storage.type", "var" ], + [ "text", " " ], + [ "identifier", "max_time" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "constant.numeric", "100" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "storage.type", "var" ], + [ "text", " " ], + [ "identifier", "hickory" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "storage.type", "var" ], + [ "text", " " ], + [ "identifier", "dickory" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "storage.type", "var" ], + [ "text", " " ], + [ "identifier", "dock" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "storage.type", "var" ], + [ "text", " " ], + [ "identifier", "i" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "js-start", + "data": [] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "storage.type", "function" ], + [ "text", " " ], + [ "entity.name.function", "StartAnimation" ], + [ "paren.lparen", "(" ], + [ "variable.parameter", "evt" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "identifier", "hickory" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "identifier", "evt" ], + [ "punctuation.operator", "." ], + [ "identifier", "target" ], + [ "punctuation.operator", "." ], + [ "identifier", "ownerDocument" ], + [ "punctuation.operator", "." ], + [ "support.function.dom", "getElementById" ], + [ "paren.lparen", "(" ], + [ "string", "\"hickory\"" ], + [ "paren.rparen", ")" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "identifier", "dickory" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "identifier", "evt" ], + [ "punctuation.operator", "." ], + [ "identifier", "target" ], + [ "punctuation.operator", "." ], + [ "identifier", "ownerDocument" ], + [ "punctuation.operator", "." ], + [ "support.function.dom", "getElementById" ], + [ "paren.lparen", "(" ], + [ "string", "\"dickory\"" ], + [ "paren.rparen", ")" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "identifier", "dock" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "identifier", "evt" ], + [ "punctuation.operator", "." ], + [ "identifier", "target" ], + [ "punctuation.operator", "." ], + [ "identifier", "ownerDocument" ], + [ "punctuation.operator", "." ], + [ "support.function.dom", "getElementById" ], + [ "paren.lparen", "(" ], + [ "string", "\"dock\"" ], + [ "paren.rparen", ")" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "js-start", + "data": [] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "identifier", "ShowAndGrowElement" ], + [ "paren.lparen", "(" ], + [ "paren.rparen", ")" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "js-start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "storage.type", "function" ], + [ "text", " " ], + [ "entity.name.function", "ShowAndGrowElement" ], + [ "paren.lparen", "(" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "identifier", "timevalue" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "identifier", "timevalue" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "text", " " ], + [ "identifier", "timer_increment" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "js-start", + "data": [ + [ "text", " " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "identifier", "timevalue" ], + [ "text", " " ], + [ "keyword.operator", ">" ], + [ "text", " " ], + [ "identifier", "max_time" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "keyword", "return" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "js-start", + "data": [ + [ "text", " " ], + [ "comment", "// Scale the text string gradually until it is 20 times larger" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "identifier", "scalefactor" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "identifier", "timevalue" ], + [ "text", " " ], + [ "keyword.operator", "*" ], + [ "text", " " ], + [ "constant.numeric", "650" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "keyword.operator", "/" ], + [ "text", " " ], + [ "identifier", "max_time" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "js-start", + "data": [] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "identifier", "timevalue" ], + [ "text", " " ], + [ "keyword.operator", "<" ], + [ "text", " " ], + [ "constant.numeric", "30" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "identifier", "hickory" ], + [ "punctuation.operator", "." ], + [ "support.function.dom", "setAttribute" ], + [ "paren.lparen", "(" ], + [ "string", "\"display\"" ], + [ "punctuation.operator", "," ], + [ "text", " " ], + [ "string", "\"\"" ], + [ "paren.rparen", ")" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "identifier", "hickory" ], + [ "punctuation.operator", "." ], + [ "support.function.dom", "setAttribute" ], + [ "paren.lparen", "(" ], + [ "string", "\"transform\"" ], + [ "punctuation.operator", "," ], + [ "text", " " ], + [ "string", "\"translate(\"" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "constant.numeric", "600" ], + [ "keyword.operator", "+" ], + [ "identifier", "scalefactor" ], + [ "keyword.operator", "*" ], + [ "constant.numeric", "3" ], + [ "keyword.operator", "*" ], + [ "constant.numeric", "-1" ], + [ "text", " " ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "text", " " ], + [ "string", "\", -144 )\"" ], + [ "paren.rparen", ")" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "js-start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "js-start", + "data": [] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "identifier", "timevalue" ], + [ "text", " " ], + [ "keyword.operator", ">" ], + [ "text", " " ], + [ "constant.numeric", "30" ], + [ "text", " " ], + [ "keyword.operator", "&" ], + [ "keyword.operator", "&" ], + [ "text", " " ], + [ "identifier", "timevalue" ], + [ "text", " " ], + [ "keyword.operator", "<" ], + [ "text", " " ], + [ "constant.numeric", "66" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "identifier", "dickory" ], + [ "punctuation.operator", "." ], + [ "support.function.dom", "setAttribute" ], + [ "paren.lparen", "(" ], + [ "string", "\"display\"" ], + [ "punctuation.operator", "," ], + [ "text", " " ], + [ "string", "\"\"" ], + [ "paren.rparen", ")" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "identifier", "dickory" ], + [ "punctuation.operator", "." ], + [ "support.function.dom", "setAttribute" ], + [ "paren.lparen", "(" ], + [ "string", "\"transform\"" ], + [ "punctuation.operator", "," ], + [ "text", " " ], + [ "string", "\"translate(\"" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "constant.numeric", "-795" ], + [ "keyword.operator", "+" ], + [ "identifier", "scalefactor" ], + [ "keyword.operator", "*" ], + [ "constant.numeric", "2" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "text", " " ], + [ "string", "\", 0 )\"" ], + [ "paren.rparen", ")" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "js-start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "identifier", "timevalue" ], + [ "text", " " ], + [ "keyword.operator", ">" ], + [ "text", " " ], + [ "constant.numeric", "66" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "identifier", "dock" ], + [ "punctuation.operator", "." ], + [ "support.function.dom", "setAttribute" ], + [ "paren.lparen", "(" ], + [ "string", "\"display\"" ], + [ "punctuation.operator", "," ], + [ "text", " " ], + [ "string", "\"\"" ], + [ "paren.rparen", ")" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "js-regex_allowed", + "data": [ + [ "text", " " ], + [ "identifier", "dock" ], + [ "punctuation.operator", "." ], + [ "support.function.dom", "setAttribute" ], + [ "paren.lparen", "(" ], + [ "string", "\"transform\"" ], + [ "punctuation.operator", "," ], + [ "text", " " ], + [ "string", "\"translate(\"" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "text", " " ], + [ "paren.lparen", "(" ], + [ "constant.numeric", "1450" ], + [ "keyword.operator", "+" ], + [ "identifier", "scalefactor" ], + [ "keyword.operator", "*" ], + [ "constant.numeric", "2" ], + [ "keyword.operator", "*" ], + [ "constant.numeric", "-1" ], + [ "paren.rparen", ")" ], + [ "text", " " ], + [ "keyword.operator", "+" ], + [ "text", " " ], + [ "string", "\", 144 )\"" ], + [ "paren.rparen", ")" ], + [ "punctuation.operator", ";" ] + ] + }, + { + "state": "js-start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "js-start", + "data": [] + }, + { + "state": "js-start", + "data": [ + [ "text", " " ], + [ "comment", "// Call ShowAndGrowElement again milliseconds later." ] + ] + }, + { + "state": "js-start", + "data": [ + [ "text", " " ], + [ "identifier", "setTimeout" ], + [ "paren.lparen", "(" ], + [ "string", "\"ShowAndGrowElement()\"" ], + [ "punctuation.operator", "," ], + [ "text", " " ], + [ "identifier", "timer_increment" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "js-start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "}" ] + ] + }, + { + "state": "js-start", + "data": [ + [ "text", " " ], + [ "variable.language", "window" ], + [ "punctuation.operator", "." ], + [ "identifier", "ShowAndGrowElement" ], + [ "text", " " ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "identifier", "ShowAndGrowElement" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "paren.rparen", "]" ], + [ "paren.rparen", "]" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "rect" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "fill" ], + [ "keyword.operator", "=" ], + [ "string", "\"#2e3436\"" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "fill-rule" ], + [ "keyword.operator", "=" ], + [ "string", "\"nonzero\"" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "stroke-width" ], + [ "keyword.operator", "=" ], + [ "string", "\"3\"" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "y" ], + [ "keyword.operator", "=" ], + [ "string", "\"0\"" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "x" ], + [ "keyword.operator", "=" ], + [ "string", "\"0\"" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "height" ], + [ "keyword.operator", "=" ], + [ "string", "\"600\"" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "width" ], + [ "keyword.operator", "=" ], + [ "string", "\"800\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "id" ], + [ "keyword.operator", "=" ], + [ "string", "\"rect3590\"" ], + [ "meta.tag", "/>" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "text" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "style" ], + [ "keyword.operator", "=" ], + [ "string", "\"font-size:144px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold\"" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "x" ], + [ "keyword.operator", "=" ], + [ "string", "\"50\"" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "y" ], + [ "keyword.operator", "=" ], + [ "string", "\"350\"" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "id" ], + [ "keyword.operator", "=" ], + [ "string", "\"hickory\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "display" ], + [ "keyword.operator", "=" ], + [ "string", "\"none\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " Hickory," ], + [ "meta.tag", "" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "text" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "style" ], + [ "keyword.operator", "=" ], + [ "string", "\"font-size:144px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold\"" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "x" ], + [ "keyword.operator", "=" ], + [ "string", "\"50\"" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "y" ], + [ "keyword.operator", "=" ], + [ "string", "\"350\"" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "id" ], + [ "keyword.operator", "=" ], + [ "string", "\"dickory\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "display" ], + [ "keyword.operator", "=" ], + [ "string", "\"none\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " dickory," ], + [ "meta.tag", "" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "text" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "style" ], + [ "keyword.operator", "=" ], + [ "string", "\"font-size:144px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold\"" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "x" ], + [ "keyword.operator", "=" ], + [ "string", "\"50\"" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "y" ], + [ "keyword.operator", "=" ], + [ "string", "\"350\"" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "id" ], + [ "keyword.operator", "=" ], + [ "string", "\"dock\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "display" ], + [ "keyword.operator", "=" ], + [ "string", "\"none\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " dock!" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_tcl.json b/lib/ace/mode/_test/tokens_tcl.json new file mode 100644 index 0000000000..2f13af3e32 --- /dev/null +++ b/lib/ace/mode/_test/tokens_tcl.json @@ -0,0 +1,536 @@ +[ + { + "state": "commandItem", + "data": [] + }, + { + "state": "commandItem", + "data": [ + [ "keyword", "proc" ], + [ "text", " " ], + [ "identifier", "dijkstra" ], + [ "text", " " ], + [ "paren.lparen", "{" ], + [ "keyword", "graph" ], + [ "text", " " ], + [ "identifier", "origin" ], + [ "paren.rparen", "}" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "comment", "# Initialize" ] + ] + }, + { + "state": "commandItem", + "data": [ + [ "text", " " ], + [ "keyword", "dict" ], + [ "text", " " ], + [ "identifier", "for" ], + [ "text", " " ], + [ "paren.lparen", "{" ], + [ "keyword", "vertex" ], + [ "text", " " ], + [ "identifier", "distmap" ], + [ "paren.rparen", "}" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "graph" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "keyword", "dict" ], + [ "text", " " ], + [ "identifier", "set" ], + [ "text", " " ], + [ "identifier", "dist" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "vertex" ], + [ "text", " " ], + [ "identifier", "Inf" ] + ] + }, + { + "state": "commandItem", + "data": [ + [ "text", "\t" ], + [ "keyword", "dict" ], + [ "text", " " ], + [ "identifier", "set" ], + [ "text", " " ], + [ "identifier", "path" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "vertex" ], + [ "text", " " ], + [ "paren.lparen", "{" ], + [ "text", "}" ] + ] + }, + { + "state": "commandItem", + "data": [ + [ "text", " }" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "dict" ], + [ "text", " " ], + [ "identifier", "set" ], + [ "text", " " ], + [ "identifier", "dist" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "origin" ], + [ "text", " 0" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "dict" ], + [ "text", " " ], + [ "identifier", "set" ], + [ "text", " " ], + [ "identifier", "path" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "origin" ], + [ "text", " " ], + [ "paren.lparen", "[" ], + [ "keyword", "list" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "origin" ], + [ "paren.rparen", "]" ] + ] + }, + { + "state": "commandItem", + "data": [ + [ "text", " " ] + ] + }, + { + "state": "commandItem", + "data": [ + [ "text", " " ], + [ "keyword", "while" ], + [ "text", " " ], + [ "paren.lparen", "{" ], + [ "text", "[" ], + [ "keyword", "dict" ], + [ "text", " " ], + [ "identifier", "size" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "graph" ], + [ "paren.rparen", "]" ], + [ "paren.rparen", "}" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "comment", "# Find unhandled node with least weight" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "keyword", "set" ], + [ "text", " " ], + [ "identifier", "d" ], + [ "text", " " ], + [ "identifier", "Inf" ] + ] + }, + { + "state": "commandItem", + "data": [ + [ "text", "\t" ], + [ "keyword", "dict" ], + [ "text", " " ], + [ "identifier", "for" ], + [ "text", " " ], + [ "paren.lparen", "{" ], + [ "keyword", "uu" ], + [ "text", " " ], + [ "support.function", "-" ], + [ "paren.rparen", "}" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "graph" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "commandItem", + "data": [ + [ "text", "\t " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "paren.lparen", "{" ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "d" ], + [ "text", " " ], + [ "support.function", ">" ], + [ "text", " " ], + [ "paren.lparen", "[" ], + [ "keyword", "set" ], + [ "text", " " ], + [ "identifier", "dd" ], + [ "text", " " ], + [ "paren.lparen", "[" ], + [ "keyword", "dict" ], + [ "text", " " ], + [ "identifier", "get" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "dist" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "uu" ], + [ "paren.rparen", "]" ], + [ "paren.rparen", "]" ], + [ "paren.rparen", "}" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t\t" ], + [ "keyword", "set" ], + [ "text", " " ], + [ "identifier", "u" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "uu" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t\t" ], + [ "keyword", "set" ], + [ "text", " " ], + [ "identifier", "d" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "dd" ] + ] + }, + { + "state": "commandItem", + "data": [ + [ "text", "\t }" ] + ] + }, + { + "state": "commandItem", + "data": [ + [ "text", "\t}" ] + ] + }, + { + "state": "commandItem", + "data": [ + [ "text", " " ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "comment", "# No such node; graph must be disconnected" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "keyword", "if" ], + [ "text", " " ], + [ "paren.lparen", "{" ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "d" ], + [ "text", " " ], + [ "support.function", "==" ], + [ "text", " " ], + [ "identifier", "Inf" ], + [ "paren.rparen", "}" ], + [ "text", " " ], + [ "identifier", "break" ] + ] + }, + { + "state": "commandItem", + "data": [ + [ "text", " " ] + ] + }, + { + "state": "commentfollow", + "data": [ + [ "text", "\t" ], + [ "comment", "# Update the weights for nodes\\" ] + ] + }, + { + "state": "start", + "data": [ + [ "comment", "\t lead to by the node we've picked" ] + ] + }, + { + "state": "commandItem", + "data": [ + [ "text", "\t" ], + [ "keyword", "dict" ], + [ "text", " " ], + [ "identifier", "for" ], + [ "text", " " ], + [ "paren.lparen", "{" ], + [ "keyword", "v" ], + [ "text", " " ], + [ "identifier", "dd" ], + [ "paren.rparen", "}" ], + [ "text", " " ], + [ "paren.lparen", "[" ], + [ "keyword", "dict" ], + [ "text", " " ], + [ "identifier", "get" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "graph" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "u" ], + [ "paren.rparen", "]" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "commandItem", + "data": [ + [ "text", "\t " ], + [ "keyword", "if" ], + [ "text", " " ], + [ "paren.lparen", "{" ], + [ "text", "[" ], + [ "keyword", "dict" ], + [ "text", " " ], + [ "identifier", "exists" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "graph" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "v" ], + [ "paren.rparen", "]" ], + [ "paren.rparen", "}" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t\t" ], + [ "keyword", "set" ], + [ "text", " " ], + [ "identifier", "alt" ], + [ "text", " " ], + [ "paren.lparen", "[" ], + [ "keyword", "expr" ], + [ "text", " " ], + [ "paren.lparen", "{" ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "d" ], + [ "text", " " ], + [ "support.function", "+" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "dd" ], + [ "paren.rparen", "}" ], + [ "paren.rparen", "]" ] + ] + }, + { + "state": "commandItem", + "data": [ + [ "text", "\t\t" ], + [ "keyword", "if" ], + [ "text", " " ], + [ "paren.lparen", "{" ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "alt" ], + [ "text", " " ], + [ "support.function", "<" ], + [ "text", " " ], + [ "paren.lparen", "[" ], + [ "keyword", "dict" ], + [ "text", " " ], + [ "identifier", "get" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "dist" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "v" ], + [ "paren.rparen", "]" ], + [ "paren.rparen", "}" ], + [ "text", " " ], + [ "paren.lparen", "{" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t\t " ], + [ "keyword", "dict" ], + [ "text", " " ], + [ "identifier", "set" ], + [ "text", " " ], + [ "identifier", "dist" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "v" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "alt" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t\t " ], + [ "keyword", "dict" ], + [ "text", " " ], + [ "identifier", "set" ], + [ "text", " " ], + [ "identifier", "path" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "v" ], + [ "text", " " ], + [ "paren.lparen", "[" ], + [ "keyword", "list" ], + [ "text", " " ], + [ "support.function", "{*}" ], + [ "paren.lparen", "[" ], + [ "keyword", "dict" ], + [ "text", " " ], + [ "identifier", "get" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "path" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "u" ], + [ "paren.rparen", "]" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "v" ], + [ "paren.rparen", "]" ] + ] + }, + { + "state": "commandItem", + "data": [ + [ "text", "\t\t}" ] + ] + }, + { + "state": "commandItem", + "data": [ + [ "text", "\t }" ] + ] + }, + { + "state": "commandItem", + "data": [ + [ "text", "\t}" ] + ] + }, + { + "state": "commandItem", + "data": [ + [ "text", " " ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "comment", "# Remove chosen node from graph still to be handled" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "\t" ], + [ "keyword", "dict" ], + [ "text", " " ], + [ "identifier", "unset" ], + [ "text", " " ], + [ "identifier", "graph" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "u" ] + ] + }, + { + "state": "commandItem", + "data": [ + [ "text", " }" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "keyword", "return" ], + [ "text", " " ], + [ "paren.lparen", "[" ], + [ "keyword", "list" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "dist" ], + [ "text", " " ], + [ "variable.instancce", "$" ], + [ "variable.instancce", "path" ], + [ "paren.rparen", "]" ] + ] + }, + { + "state": "commandItem", + "data": [ + [ "text", "}" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_text.json b/lib/ace/mode/_test/tokens_text.json new file mode 100644 index 0000000000..b74923cd8d --- /dev/null +++ b/lib/ace/mode/_test/tokens_text.json @@ -0,0 +1,58 @@ +[ + { + "state": "start", + "data": [ + [ "text", "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_textile.json b/lib/ace/mode/_test/tokens_textile.json new file mode 100644 index 0000000000..beb947bca0 --- /dev/null +++ b/lib/ace/mode/_test/tokens_textile.json @@ -0,0 +1,195 @@ +[ + { + "state": "start", + "data": [ + [ "markup.heading.1", "h1" ], + [ "keyword", ". " ], + [ "text", "Textile document" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "markup.heading.2", "h2" ], + [ "keyword", ". " ], + [ "text", "Heading Two" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "markup.heading.3", "h3" ], + [ "keyword", ". " ], + [ "text", "A two-line" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " header" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "markup.heading.2", "h2" ], + [ "keyword", ". " ], + [ "text", "Another two-line" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "header" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "Paragraph:" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "one, two," ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "thee lines!" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "markup.heading", "p" ], + [ "keyword", "(" ], + [ "string", "classone" ], + [ "text", " " ], + [ "string", "two" ], + [ "text", " " ], + [ "string", "three" ], + [ "keyword", ")" ], + [ "keyword", ". " ], + [ "text", "This is a paragraph with classes" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "markup.heading", "p" ], + [ "keyword", "(" ], + [ "keyword", "#" ], + [ "string", "id" ], + [ "keyword", ")" ], + [ "keyword", ". " ], + [ "text", "(one with an id)" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "markup.heading", "p" ], + [ "keyword", "(" ], + [ "string", "one" ], + [ "text", " " ], + [ "string", "two" ], + [ "text", " " ], + [ "string", "three" ], + [ "keyword", "#" ], + [ "string", "my_id" ], + [ "keyword", ")" ], + [ "keyword", ". " ], + [ "text", "..classes + id" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "*" ], + [ "text", " Unordered list" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "**" ], + [ "text", " sublist" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "*" ], + [ "text", " back again!" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "**" ], + [ "text", " sublist again.." ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "#" ], + [ "text", " ordered" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "bg. Blockquote!" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " This is a two-list blockquote..!" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_xml.json b/lib/ace/mode/_test/tokens_xml.json new file mode 100644 index 0000000000..b7c9dcfdb4 --- /dev/null +++ b/lib/ace/mode/_test/tokens_xml.json @@ -0,0 +1,705 @@ +[ + { + "state": "start", + "data": [ + [ "xml-pe", "" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "query" ], + [ "text", " " ], + [ "entity.other.attribute-name", "xmlns:yahoo" ], + [ "keyword.operator", "=" ], + [ "string", "\"http://www.yahooapis.com/v1/base.rng\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "yahoo:count" ], + [ "keyword.operator", "=" ], + [ "string", "\"7\"" ], + [ "text", " " ], + [ "entity.other.attribute-name", "yahoo:created" ], + [ "keyword.operator", "=" ], + [ "string", "\"2011-10-11T08:40:23Z\"" ], + [ "text", " " ], + [ "entity.other.attribute-name", "yahoo:lang" ], + [ "keyword.operator", "=" ], + [ "string", "\"en-US\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "diagnostics" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "publiclyCallable" ], + [ "meta.tag", ">" ], + [ "text", "true" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "url" ], + [ "text", " " ], + [ "entity.other.attribute-name", "execution-start-time" ], + [ "keyword.operator", "=" ], + [ "string", "\"0\"" ], + [ "text", " " ], + [ "entity.other.attribute-name", "execution-stop-time" ], + [ "keyword.operator", "=" ], + [ "string", "\"25\"" ], + [ "text", " " ], + [ "entity.other.attribute-name", "execution-time" ], + [ "keyword.operator", "=" ], + [ "string", "\"25\"" ], + [ "meta.tag", ">" ], + [ "text", "" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "user-time" ], + [ "meta.tag", ">" ], + [ "text", "26" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "service-time" ], + [ "meta.tag", ">" ], + [ "text", "25" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "build-version" ], + [ "meta.tag", ">" ], + [ "text", "21978" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "" ], + [ "text", " " ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "results" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "place" ], + [ "text", " " ], + [ "entity.other.attribute-name", "xmlns" ], + [ "keyword.operator", "=" ], + [ "string", "\"http://where.yahooapis.com/v1/schema.rng\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "xml:lang" ], + [ "keyword.operator", "=" ], + [ "string", "\"en-US\"" ], + [ "text", " " ], + [ "entity.other.attribute-name", "yahoo:uri" ], + [ "keyword.operator", "=" ], + [ "string", "\"http://where.yahooapis.com/v1/place/24865670\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "woeid" ], + [ "meta.tag", ">" ], + [ "text", "24865670" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "placeTypeName" ], + [ "text", " " ], + [ "entity.other.attribute-name", "code" ], + [ "keyword.operator", "=" ], + [ "string", "\"29\"" ], + [ "meta.tag", ">" ], + [ "text", "Continent" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "name" ], + [ "meta.tag", ">" ], + [ "text", "Africa" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "place" ], + [ "text", " " ], + [ "entity.other.attribute-name", "xmlns" ], + [ "keyword.operator", "=" ], + [ "string", "\"http://where.yahooapis.com/v1/schema.rng\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "xml:lang" ], + [ "keyword.operator", "=" ], + [ "string", "\"en-US\"" ], + [ "text", " " ], + [ "entity.other.attribute-name", "yahoo:uri" ], + [ "keyword.operator", "=" ], + [ "string", "\"http://where.yahooapis.com/v1/place/24865675\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "woeid" ], + [ "meta.tag", ">" ], + [ "text", "24865675" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "placeTypeName" ], + [ "text", " " ], + [ "entity.other.attribute-name", "code" ], + [ "keyword.operator", "=" ], + [ "string", "\"29\"" ], + [ "meta.tag", ">" ], + [ "text", "Continent" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "name" ], + [ "meta.tag", ">" ], + [ "text", "Europe" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "place" ], + [ "text", " " ], + [ "entity.other.attribute-name", "xmlns" ], + [ "keyword.operator", "=" ], + [ "string", "\"http://where.yahooapis.com/v1/schema.rng\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "xml:lang" ], + [ "keyword.operator", "=" ], + [ "string", "\"en-US\"" ], + [ "text", " " ], + [ "entity.other.attribute-name", "yahoo:uri" ], + [ "keyword.operator", "=" ], + [ "string", "\"http://where.yahooapis.com/v1/place/24865673\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "woeid" ], + [ "meta.tag", ">" ], + [ "text", "24865673" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "placeTypeName" ], + [ "text", " " ], + [ "entity.other.attribute-name", "code" ], + [ "keyword.operator", "=" ], + [ "string", "\"29\"" ], + [ "meta.tag", ">" ], + [ "text", "Continent" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "name" ], + [ "meta.tag", ">" ], + [ "text", "South America" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "place" ], + [ "text", " " ], + [ "entity.other.attribute-name", "xmlns" ], + [ "keyword.operator", "=" ], + [ "string", "\"http://where.yahooapis.com/v1/schema.rng\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "xml:lang" ], + [ "keyword.operator", "=" ], + [ "string", "\"en-US\"" ], + [ "text", " " ], + [ "entity.other.attribute-name", "yahoo:uri" ], + [ "keyword.operator", "=" ], + [ "string", "\"http://where.yahooapis.com/v1/place/28289421\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "woeid" ], + [ "meta.tag", ">" ], + [ "text", "28289421" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "placeTypeName" ], + [ "text", " " ], + [ "entity.other.attribute-name", "code" ], + [ "keyword.operator", "=" ], + [ "string", "\"29\"" ], + [ "meta.tag", ">" ], + [ "text", "Continent" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "name" ], + [ "meta.tag", ">" ], + [ "text", "Antarctic" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "place" ], + [ "text", " " ], + [ "entity.other.attribute-name", "xmlns" ], + [ "keyword.operator", "=" ], + [ "string", "\"http://where.yahooapis.com/v1/schema.rng\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "xml:lang" ], + [ "keyword.operator", "=" ], + [ "string", "\"en-US\"" ], + [ "text", " " ], + [ "entity.other.attribute-name", "yahoo:uri" ], + [ "keyword.operator", "=" ], + [ "string", "\"http://where.yahooapis.com/v1/place/24865671\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "woeid" ], + [ "meta.tag", ">" ], + [ "text", "24865671" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "placeTypeName" ], + [ "text", " " ], + [ "entity.other.attribute-name", "code" ], + [ "keyword.operator", "=" ], + [ "string", "\"29\"" ], + [ "meta.tag", ">" ], + [ "text", "Continent" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "name" ], + [ "meta.tag", ">" ], + [ "text", "Asia" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "place" ], + [ "text", " " ], + [ "entity.other.attribute-name", "xmlns" ], + [ "keyword.operator", "=" ], + [ "string", "\"http://where.yahooapis.com/v1/schema.rng\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "xml:lang" ], + [ "keyword.operator", "=" ], + [ "string", "\"en-US\"" ], + [ "text", " " ], + [ "entity.other.attribute-name", "yahoo:uri" ], + [ "keyword.operator", "=" ], + [ "string", "\"http://where.yahooapis.com/v1/place/24865672\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "woeid" ], + [ "meta.tag", ">" ], + [ "text", "24865672" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "placeTypeName" ], + [ "text", " " ], + [ "entity.other.attribute-name", "code" ], + [ "keyword.operator", "=" ], + [ "string", "\"29\"" ], + [ "meta.tag", ">" ], + [ "text", "Continent" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "name" ], + [ "meta.tag", ">" ], + [ "text", "North America" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "" ] + ] + }, + { + "state": "tag_embed_attribute_list", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "place" ], + [ "text", " " ], + [ "entity.other.attribute-name", "xmlns" ], + [ "keyword.operator", "=" ], + [ "string", "\"http://where.yahooapis.com/v1/schema.rng\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "entity.other.attribute-name", "xml:lang" ], + [ "keyword.operator", "=" ], + [ "string", "\"en-US\"" ], + [ "text", " " ], + [ "entity.other.attribute-name", "yahoo:uri" ], + [ "keyword.operator", "=" ], + [ "string", "\"http://where.yahooapis.com/v1/place/55949070\"" ], + [ "meta.tag", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "woeid" ], + [ "meta.tag", ">" ], + [ "text", "55949070" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "placeTypeName" ], + [ "text", " " ], + [ "entity.other.attribute-name", "code" ], + [ "keyword.operator", "=" ], + [ "string", "\"29\"" ], + [ "meta.tag", ">" ], + [ "text", "Continent" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "<" ], + [ "meta.tag.tag-name", "name" ], + [ "meta.tag", ">" ], + [ "text", "Australia" ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "meta.tag", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "meta.tag", "" ] + ] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_xquery.json b/lib/ace/mode/_test/tokens_xquery.json new file mode 100644 index 0000000000..62d9c9273c --- /dev/null +++ b/lib/ace/mode/_test/tokens_xquery.json @@ -0,0 +1,64 @@ +[ + { + "state": "start", + "data": [ + [ "keyword", "xquery" ], + [ "text", " " ], + [ "keyword", "version" ], + [ "text", " " ], + [ "string", "\"1.0\"" ], + [ "text", ";" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "keyword", "let" ], + [ "text", " " ], + [ "variable", "$message" ], + [ "text", " :" ], + [ "keyword.operator", "=" ], + [ "text", " " ], + [ "string", "\"Hello World!\"" ] + ] + }, + { + "state": "start", + "data": [ + [ "keyword", "return" ], + [ "text", " <" ], + [ "meta.tag", "results" ], + [ "text", ">" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " <" ], + [ "meta.tag", "message" ], + [ "text", ">" ], + [ "lparen", "{" ], + [ "variable", "$message" ], + [ "rparen", "}" ], + [ "text", "" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", "" ] + ] + }, + { + "state": "start", + "data": [] + } +] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_yaml.json b/lib/ace/mode/_test/tokens_yaml.json new file mode 100644 index 0000000000..9a8c1ce783 --- /dev/null +++ b/lib/ace/mode/_test/tokens_yaml.json @@ -0,0 +1,260 @@ +[ + { + "state": "start", + "data": [ + [ "comment", "# This sample document was taken from wikipedia:" ] + ] + }, + { + "state": "start", + "data": [ + [ "comment", "# http://en.wikipedia.org/wiki/YAML#Sample_document" ] + ] + }, + { + "state": "start", + "data": [ + [ "comment", "---" ] + ] + }, + { + "state": "start", + "data": [ + [ "identifier", "receipt:" ], + [ "text", " Oz-Ware Purchase Invoice" ] + ] + }, + { + "state": "start", + "data": [ + [ "identifier", "date:" ], + [ "text", " " ], + [ "constant.numeric", "2007" ], + [ "constant.numeric", "-08" ], + [ "constant.numeric", "-06" ] + ] + }, + { + "state": "start", + "data": [ + [ "identifier", "customer:" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "given:" ], + [ "text", " Dorothy" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "family:" ], + [ "text", " Gale" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "identifier", "items:" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " - " ], + [ "identifier", "part_no:" ], + [ "text", " " ], + [ "string", "'A4786'" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "descrip:" ], + [ "text", " Water Bucket " ], + [ "paren.lparen", "(" ], + [ "text", "Filled" ], + [ "paren.rparen", ")" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "price:" ], + [ "text", " " ], + [ "constant.numeric", "1.47" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "quantity:" ], + [ "text", " " ], + [ "constant.numeric", "4" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", " - " ], + [ "identifier", "part_no:" ], + [ "text", " " ], + [ "string", "'E1628'" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "descrip:" ], + [ "text", " High Heeled " ], + [ "string", "\"Ruby\"" ], + [ "text", " Slippers" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "size:" ], + [ "text", " " ], + [ "constant.numeric", "8" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "price:" ], + [ "text", " " ], + [ "constant.numeric", "100.27" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "quantity:" ], + [ "text", " " ], + [ "constant.numeric", "1" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "bill-" ], + [ "identifier", "to:" ], + [ "text", " " ], + [ "variable", "&id001" ] + ] + }, + { + "state": "qqstring", + "data": [ + [ "text", " " ], + [ "identifier", "street:" ], + [ "text", " " ], + [ "string", "|" ] + ] + }, + { + "state": "qqstring", + "data": [ + [ "string", " 123 Tornado Alley" ] + ] + }, + { + "state": "qqstring", + "data": [ + [ "string", " Suite 16" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "city:" ], + [ "text", " East Centerville" ] + ] + }, + { + "state": "start", + "data": [ + [ "text", " " ], + [ "identifier", "state:" ], + [ "text", " KS" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "start", + "data": [ + [ "text", "ship-" ], + [ "identifier", "to:" ], + [ "text", " " ], + [ "variable", "*id001" ] + ] + }, + { + "state": "start", + "data": [] + }, + { + "state": "qqstring", + "data": [ + [ "identifier", "specialDelivery:" ], + [ "text", " " ], + [ "string", ">" ] + ] + }, + { + "state": "qqstring", + "data": [ + [ "string", " Follow the Yellow Brick" ] + ] + }, + { + "state": "qqstring", + "data": [ + [ "string", " Road to the Emerald City." ] + ] + }, + { + "state": "qqstring", + "data": [ + [ "string", " Pay no attention to the" ] + ] + }, + { + "state": "qqstring", + "data": [ + [ "string", " man behind the curtain." ] + ] + }, + { + "state": "qqstring", + "data": [] + } +] \ No newline at end of file diff --git a/lib/ace/mode/asciidoc.js b/lib/ace/mode/asciidoc.js new file mode 100644 index 0000000000..b4e83f675e --- /dev/null +++ b/lib/ace/mode/asciidoc.js @@ -0,0 +1,64 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var Tokenizer = require("../tokenizer").Tokenizer; +var AsciidocHighlightRules = require("./asciidoc_highlight_rules").AsciidocHighlightRules; +var AsciidocFoldMode = require("./folding/asciidoc").FoldMode; + +var Mode = function() { + var highlighter = new AsciidocHighlightRules(); + + this.$tokenizer = new Tokenizer(highlighter.getRules()); + this.foldingRules = new AsciidocFoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + this.getNextLineIndent = function(state, line, tab) { + if (state == "listblock") { + var match = /^((?:.+)?)([-+*][ ]+)/.exec(line); + if (match) { + return new Array(match[1].length + 1).join(" ") + match[2]; + } else { + return ""; + } + } else { + return this.$getIndent(line); + } + }; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); diff --git a/lib/ace/mode/asciidoc_highlight_rules.js b/lib/ace/mode/asciidoc_highlight_rules.js new file mode 100644 index 0000000000..24eeafd74c --- /dev/null +++ b/lib/ace/mode/asciidoc_highlight_rules.js @@ -0,0 +1,233 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var AsciidocHighlightRules = function() { + var identifierRe = "[a-zA-Z\u00a1-\uffff]+\\b"; + + this.$rules = { + "start": [ + {token: "empty", regex: /$/}, + {token: "literal", regex: /^\.{4,}\s*$/, next: "listingBlock"}, + {token: "literal", regex: /^-{4,}\s*$/, next: "literalBlock"}, + {token: "string", regex: /^\+{4,}\s*$/, next: "passthroughBlock"}, + {token: "keyword", regex: /^={4,}\s*$/}, + {token: "text", regex: /^\s*$/}, + // immediately return to the start mode without matching anything + {token: "empty", regex: "", next: "dissallowDelimitedBlock"} + ], + + "dissallowDelimitedBlock": [ + {include: "paragraphEnd"}, + {token: "comment", regex: '^//.+$'}, + {token: "keyword", regex: "^(?:NOTE|TIP|IMPORTANT|WARNING|CAUTION):"}, + + {include: "listStart"}, + {token: "literal", regex: /^\s+.+$/, next: "indentedBlock"}, + {token: "empty", regex: "", next: "text"} + ], + + "paragraphEnd": [ + {token: "doc.comment", regex: /^\/{4,}\s*$/, next: "commentBlock"}, + {token: "tableBlock", regex: /^\s*[|!]=+\s*$/, next: "tableBlock"}, + // open block, ruller + {token: "keyword", regex: /^(?:--|''')\s*$/, next: "start"}, + {token: "option", regex: /^\[.*\]\s*$/, next: "start"}, + {token: "pageBreak", regex: /^>{3,}$/, next: "start"}, + {token: "literal", regex: /^\.{4,}\s*$/, next: "listingBlock"}, + {token: "titleUnderline", regex: /^(?:={2,}|-{2,}|~{2,}|\^{2,}|\+{2,})\s*$/, next: "start"}, + {token: "singleLineTitle", regex: /^={1,5}\s+\S.*$/, next: "start"}, + + {token: "otherBlock", regex: /^(?:\*{2,}|_{2,})\s*$/, next: "start"}, + // .optional title + {token: "optionalTitle", regex: /^\.[^.\s].+$/, next: "start"} + ], + + "listStart": [ + {token: "keyword", regex: /^\s*(?:\d+\.|[a-zA-Z]\.|[ixvmIXVM]+\)|\*{1,5}|-|\.{1,5})\s/, next: "listText"}, + {token: "meta.tag", regex: /^.+(?::{2,4}|;;)(?: |$)/, next: "listText"}, + {token: "support.function.list.callout", regex: /^(?:<\d+>|\d+>|>) /, next: "text"}, + // continuation + {token: "keyword", regex: /^\+\s*$/, next: "start"} + ], + + "text": [ + {token: ["link", "variable.language"], regex: /((?:https?:\/\/|ftp:\/\/|file:\/\/|mailto:|callto:)[^\s\[]+)(\[.*?\])/}, + {token: "link", regex: /(?:https?:\/\/|ftp:\/\/|file:\/\/|mailto:|callto:)[^\s\[]+/}, + {token: "link", regex: /\b[\w\.\/\-]+@[\w\.\/\-]+\b/}, + {include: "macros"}, + {include: "paragraphEnd"}, + {token: "literal", regex:/\+{3,}/, next:"smallPassthrough"}, + {token: "escape", regex: /\((?:C|TM|R)\)|\.{3}|->|<-|=>|<=|&#(?:\d+|x[a-fA-F\d]+);|(?: |^)--(?=\s+\S)/}, + {token: "escape", regex: /\\[_*'`+#]|\\{2}[_*'`+#]{2}/}, + {token: "keyword", regex: /\s\+$/}, + // any word + {token: "text", regex: identifierRe}, + {token: ["keyword", "string", "keyword"], + regex: /(<<[\w\d\-$]+,)(.*?)(>>|$)/, merge: true}, + {token: "keyword", regex: /<<[\w\d\-$]+,?|>>/, merge: true}, + {token: "constant.character", regex: /\({2,3}.*?\){2,3}/, merge: true}, + // Anchor + {token: "keyword", regex: /\[\[.+?\]\]/}, + // bibliography + {token: "support", regex: /^\[{3}[\w\d =\-]+\]{3}/}, + + {include: "quotes"}, + // text block end + {token: "empty", regex: /^\s*$/, next: "start"} + ], + + "listText": [ + {include: "listStart"}, + {include: "text"} + ], + + "indentedBlock": [ + {token: "literal", regex: /^[\s\w].+$/, next: "indentedBlock"}, + {token: "literal", regex: "", next: "start"} + ], + + "listingBlock": [ + {token: "literal", regex: /^\.{4,}\s*$/, next: "dissallowDelimitedBlock"}, + {token: "constant.numeric", regex: '<\\d+>'}, + {token: "literal", regex: '[^<]+', merge: true}, + {token: "literal", regex: '<', merge: true} + ], + "literalBlock": [ + {token: "literal", regex: /^-{4,}\s*$/, next: "dissallowDelimitedBlock"}, + {token: "constant.numeric", regex: '<\\d+>'}, + {token: "literal", regex: '[^<]+', merge: true}, + {token: "literal", regex: '<', merge: true} + ], + "passthroughBlock": [ + {token: "literal", regex: /^\+{4,}\s*$/, next: "dissallowDelimitedBlock"}, + {token: "literal", regex: identifierRe + "|\\d+", merge: true}, + {include: "macros"}, + {token: "literal", regex: ".", merge: true} + ], + + "smallPassthrough": [ + {token: "literal", regex: /[+]{3,}/, next: "dissallowDelimitedBlock"}, + {token: "literal", regex: /^\s*$/, next: "dissallowDelimitedBlock", merge: true}, + {token: "literal", regex: identifierRe + "|\\d+", merge: true}, + {include: "macros"} + ], + + "commentBlock": [ + {token: "doc.comment", regex: /^\/{4,}\s*$/, next: "dissallowDelimitedBlock"}, + {token: "doc.comment", regex: '^.*$'} + ], + "tableBlock": [ + {token: "tableBlock", regex: /^\s*\|={3,}\s*$/, next: "dissallowDelimitedBlock"}, + {token: "tableBlock", regex: /^\s*!={3,}\s*$/, next: "innerTableBlock"}, + {token: "tableBlock", regex: /\|/}, + {include: "text", noEscape: true} + ], + "innerTableBlock": [ + {token: "tableBlock", regex: /^\s*!={3,}\s*$/, next: "tableBlock"}, + {token: "tableBlock", regex: /^\s*|={3,}\s*$/, next: "dissallowDelimitedBlock"}, + {token: "tableBlock", regex: /\!/} + ], + "macros": [ + {token: "macro", regex: /{[\w\-$]+}/}, + {token: ["text", "string", "text", "constant.character", "text"], regex: /({)([\w\-$]+)(:)?(.+)?(})/}, + {token: ["markup.list.macro", "keyword", "string"], regex: /([\w\.\/\-]+::?)([^\s\[]+)(\[.*?\])?/}, + {token: ["markup.list.macro", "keyword"], regex: /([\w\.\/\-]+::?)(\[.*?\])/}, + {token: "keyword", regex: /^:.+?:(?= |$)/} + ], + + "quotes": [ + {token: "string.italic", regex: /__[^_\s].*?__/}, + {token: "string.italic", regex: quoteRule("_")}, + + {token: "keyword.bold", regex: /\*\*[^*\s].*?\*\*/}, + {token: "keyword.bold", regex: quoteRule("\\*")}, + + {token: "literal", regex: quoteRule("\\+")}, + {token: "literal", regex: /\+\+[^+\s].*?\+\+/}, + {token: "literal", regex: /\$\$.+?\$\$/}, + {token: "literal", regex: quoteRule("`")}, + + {token: "keyword", regex: quoteRule("^")}, + {token: "keyword", regex: quoteRule("~")}, + {token: "keyword", regex: /##?/}, + {token: "keyword", regex: /(?:\B|^)``|\b''/} + ] + + }; + + function quoteRule(ch) { + var prefix = /\w/.test(ch) ? "\\b" : "(?:\\B|^)"; + return prefix + ch + "[^" + ch + "].*?" + ch + "(?![\\w*])"; + } + + //addQuoteBlock("text") + + var tokenMap = { + macro: "constant.character", + tableBlock: "doc.comment", + titleUnderline: "markup.heading", + singleLineTitle: "markup.heading", + pageBreak: "string", + option: "string.regexp", + otherBlock: "markup.list", + literal: "support.function", + optionalTitle: "constant.numeric", + escape: "constant.language.escape", + link: "markup.underline.list" + }; + + for (var state in this.$rules) { + var stateRules = this.$rules[state]; + for (var i = stateRules.length; i--; ) { + var rule = stateRules[i]; + if (rule.include || typeof rule == "string") { + var args = [i, 1].concat(this.$rules[rule.include || rule]); + if (rule.noEscape) { + args = args.filter(function(x) { + return !x.next; + }); + } + stateRules.splice.apply(stateRules, args); + } else if (rule.token in tokenMap) { + rule.token = tokenMap[rule.token]; + } + } + } +}; +oop.inherits(AsciidocHighlightRules, TextHighlightRules); + +exports.AsciidocHighlightRules = AsciidocHighlightRules; +}); diff --git a/lib/ace/mode/behaviour.js b/lib/ace/mode/behaviour.js new file mode 100644 index 0000000000..c1c6cb15be --- /dev/null +++ b/lib/ace/mode/behaviour.js @@ -0,0 +1,90 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var Behaviour = function() { + this.$behaviours = {}; +}; + +(function () { + + this.add = function (name, action, callback) { + switch (undefined) { + case this.$behaviours: + this.$behaviours = {}; + case this.$behaviours[name]: + this.$behaviours[name] = {}; + } + this.$behaviours[name][action] = callback; + } + + this.addBehaviours = function (behaviours) { + for (var key in behaviours) { + for (var action in behaviours[key]) { + this.add(key, action, behaviours[key][action]); + } + } + } + + this.remove = function (name) { + if (this.$behaviours && this.$behaviours[name]) { + delete this.$behaviours[name]; + } + } + + this.inherit = function (mode, filter) { + if (typeof mode === "function") { + var behaviours = new mode().getBehaviours(filter); + } else { + var behaviours = mode.getBehaviours(filter); + } + this.addBehaviours(behaviours); + } + + this.getBehaviours = function (filter) { + if (!filter) { + return this.$behaviours; + } else { + var ret = {} + for (var i = 0; i < filter.length; i++) { + if (this.$behaviours[filter[i]]) { + ret[filter[i]] = this.$behaviours[filter[i]]; + } + } + return ret; + } + } + +}).call(Behaviour.prototype); + +exports.Behaviour = Behaviour; +}); diff --git a/lib/ace/mode/behaviour/cstyle.js b/lib/ace/mode/behaviour/cstyle.js new file mode 100644 index 0000000000..346b5867b8 --- /dev/null +++ b/lib/ace/mode/behaviour/cstyle.js @@ -0,0 +1,316 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../../lib/oop"); +var Behaviour = require("../behaviour").Behaviour; +var TokenIterator = require("../../token_iterator").TokenIterator; + +var autoInsertedBrackets = 0; +var autoInsertedRow = -1; +var autoInsertedLineEnd = ""; + +var CstyleBehaviour = function () { + + CstyleBehaviour.isSaneInsertion = function(editor, session) { + var cursor = editor.getCursorPosition(); + var iterator = new TokenIterator(session, cursor.row, cursor.column); + + // Don't insert in the middle of a keyword/identifier/lexical + if (!this.$matchTokenType(iterator.getCurrentToken() || "text", ["text", "paren.rparen"])) { + // Look ahead in case we're at the end of a token + iterator = new TokenIterator(session, cursor.row, cursor.column + 1); + if (!this.$matchTokenType(iterator.getCurrentToken() || "text", ["text", "paren.rparen"])) + return false; + } + + // Only insert in front of whitespace/comments + iterator.stepForward(); + return iterator.getCurrentTokenRow() !== cursor.row || + this.$matchTokenType(iterator.getCurrentToken() || "text", ["text", "comment", "paren.rparen"]); + }; + + CstyleBehaviour.$matchTokenType = function(token, types) { + return types.indexOf(token.type || token) > -1; + }; + + CstyleBehaviour.recordAutoInsert = function(editor, session, bracket) { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + // Reset previous state if text or context changed too much + if (!this.isAutoInsertedClosing(cursor, line, autoInsertedLineEnd[0])) + autoInsertedBrackets = 0; + autoInsertedRow = cursor.row; + autoInsertedLineEnd = bracket + line.substr(cursor.column); + autoInsertedBrackets++; + }; + + CstyleBehaviour.isAutoInsertedClosing = function(cursor, line, bracket) { + return autoInsertedBrackets > 0 && + cursor.row === autoInsertedRow && + bracket === autoInsertedLineEnd[0] && + line.substr(cursor.column) === autoInsertedLineEnd; + }; + + CstyleBehaviour.popAutoInsertedClosing = function() { + autoInsertedLineEnd = autoInsertedLineEnd.substr(1); + autoInsertedBrackets--; + }; + + this.add("braces", "insertion", function (state, action, editor, session, text) { + if (text == '{') { + var selection = editor.getSelectionRange(); + var selected = session.doc.getTextRange(selection); + if (selected !== "" && selected !== "{") { + return { + text: '{' + selected + '}', + selection: false + }; + } else if (CstyleBehaviour.isSaneInsertion(editor, session)) { + CstyleBehaviour.recordAutoInsert(editor, session, "}"); + return { + text: '{}', + selection: [1, 1] + }; + } + } else if (text == '}') { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + var rightChar = line.substring(cursor.column, cursor.column + 1); + if (rightChar == '}') { + var matching = session.$findOpeningBracket('}', {column: cursor.column + 1, row: cursor.row}); + if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) { + CstyleBehaviour.popAutoInsertedClosing(); + return { + text: '', + selection: [1, 1] + }; + } + } + } else if (text == "\n" || text == "\r\n") { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + var rightChar = line.substring(cursor.column, cursor.column + 1); + if (rightChar == '}') { + var openBracePos = session.findMatchingBracket({row: cursor.row, column: cursor.column + 1}); + if (!openBracePos) + return null; + + var indent = this.getNextLineIndent(state, line.substring(0, line.length - 1), session.getTabString()); + var next_indent = this.$getIndent(session.doc.getLine(openBracePos.row)); + + return { + text: '\n' + indent + '\n' + next_indent, + selection: [1, indent.length, 1, indent.length] + }; + } + } + }); + + this.add("braces", "deletion", function (state, action, editor, session, range) { + var selected = session.doc.getTextRange(range); + if (!range.isMultiLine() && selected == '{') { + var line = session.doc.getLine(range.start.row); + var rightChar = line.substring(range.end.column, range.end.column + 1); + if (rightChar == '}') { + range.end.column++; + return range; + } + } + }); + + this.add("parens", "insertion", function (state, action, editor, session, text) { + if (text == '(') { + var selection = editor.getSelectionRange(); + var selected = session.doc.getTextRange(selection); + if (selected !== "") { + return { + text: '(' + selected + ')', + selection: false + }; + } else if (CstyleBehaviour.isSaneInsertion(editor, session)) { + CstyleBehaviour.recordAutoInsert(editor, session, ")"); + return { + text: '()', + selection: [1, 1] + }; + } + } else if (text == ')') { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + var rightChar = line.substring(cursor.column, cursor.column + 1); + if (rightChar == ')') { + var matching = session.$findOpeningBracket(')', {column: cursor.column + 1, row: cursor.row}); + if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) { + CstyleBehaviour.popAutoInsertedClosing(); + return { + text: '', + selection: [1, 1] + }; + } + } + } + }); + + this.add("parens", "deletion", function (state, action, editor, session, range) { + var selected = session.doc.getTextRange(range); + if (!range.isMultiLine() && selected == '(') { + var line = session.doc.getLine(range.start.row); + var rightChar = line.substring(range.start.column + 1, range.start.column + 2); + if (rightChar == ')') { + range.end.column++; + return range; + } + } + }); + + this.add("brackets", "insertion", function (state, action, editor, session, text) { + if (text == '[') { + var selection = editor.getSelectionRange(); + var selected = session.doc.getTextRange(selection); + if (selected !== "") { + return { + text: '[' + selected + ']', + selection: false + }; + } else if (CstyleBehaviour.isSaneInsertion(editor, session)) { + CstyleBehaviour.recordAutoInsert(editor, session, "]"); + return { + text: '[]', + selection: [1, 1] + }; + } + } else if (text == ']') { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + var rightChar = line.substring(cursor.column, cursor.column + 1); + if (rightChar == ']') { + var matching = session.$findOpeningBracket(']', {column: cursor.column + 1, row: cursor.row}); + if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) { + CstyleBehaviour.popAutoInsertedClosing(); + return { + text: '', + selection: [1, 1] + }; + } + } + } + }); + + this.add("brackets", "deletion", function (state, action, editor, session, range) { + var selected = session.doc.getTextRange(range); + if (!range.isMultiLine() && selected == '[') { + var line = session.doc.getLine(range.start.row); + var rightChar = line.substring(range.start.column + 1, range.start.column + 2); + if (rightChar == ']') { + range.end.column++; + return range; + } + } + }); + + this.add("string_dquotes", "insertion", function (state, action, editor, session, text) { + if (text == '"' || text == "'") { + var quote = text; + var selection = editor.getSelectionRange(); + var selected = session.doc.getTextRange(selection); + if (selected !== "") { + return { + text: quote + selected + quote, + selection: false + }; + } else { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + var leftChar = line.substring(cursor.column-1, cursor.column); + + // We're escaped. + if (leftChar == '\\') { + return null; + } + + // Find what token we're inside. + var tokens = session.getTokens(selection.start.row); + var col = 0, token; + var quotepos = -1; // Track whether we're inside an open quote. + + for (var x = 0; x < tokens.length; x++) { + token = tokens[x]; + if (token.type == "string") { + quotepos = -1; + } else if (quotepos < 0) { + quotepos = token.value.indexOf(quote); + } + if ((token.value.length + col) > selection.start.column) { + break; + } + col += tokens[x].value.length; + } + + // Try and be smart about when we auto insert. + if (!token || (quotepos < 0 && token.type !== "comment" && (token.type !== "string" || ((selection.start.column !== token.value.length+col-1) && token.value.lastIndexOf(quote) === token.value.length-1)))) { + return { + text: quote + quote, + selection: [1,1] + }; + } else if (token && token.type === "string") { + // Ignore input and move right one if we're typing over the closing quote. + var rightChar = line.substring(cursor.column, cursor.column + 1); + if (rightChar == quote) { + return { + text: '', + selection: [1, 1] + }; + } + } + } + } + }); + + this.add("string_dquotes", "deletion", function (state, action, editor, session, range) { + var selected = session.doc.getTextRange(range); + if (!range.isMultiLine() && (selected == '"' || selected == "'")) { + var line = session.doc.getLine(range.start.row); + var rightChar = line.substring(range.start.column + 1, range.start.column + 2); + if (rightChar == '"') { + range.end.column++; + return range; + } + } + }); + +}; + +oop.inherits(CstyleBehaviour, Behaviour); + +exports.CstyleBehaviour = CstyleBehaviour; +}); diff --git a/lib/ace/mode/behaviour/html.js b/lib/ace/mode/behaviour/html.js new file mode 100644 index 0000000000..c15aa8b448 --- /dev/null +++ b/lib/ace/mode/behaviour/html.js @@ -0,0 +1,90 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../../lib/oop"); +var XmlBehaviour = require("../behaviour/xml").XmlBehaviour; +var CstyleBehaviour = require("./cstyle").CstyleBehaviour; +var TokenIterator = require("../../token_iterator").TokenIterator; +var voidElements = ['area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr']; + +function hasType(token, type) { + var hasType = true; + var typeList = token.type.split('.'); + var needleList = type.split('.'); + needleList.forEach(function(needle){ + if (typeList.indexOf(needle) == -1) { + hasType = false; + return false; + } + }); + return hasType; +} + +var HtmlBehaviour = function () { + + this.inherit(XmlBehaviour); // Get xml behaviour + + this.add("autoclosing", "insertion", function (state, action, editor, session, text) { + if (text == '>') { + var position = editor.getCursorPosition(); + var iterator = new TokenIterator(session, position.row, position.column); + var token = iterator.getCurrentToken(); + var atCursor = false; + if (!token || !hasType(token, 'meta.tag') && !(hasType(token, 'text') && token.value.match('/'))){ + do { + token = iterator.stepBackward(); + } while (token && (hasType(token, 'string') || hasType(token, 'keyword.operator') || hasType(token, 'entity.attribute-name') || hasType(token, 'text'))); + } else { + atCursor = true; + } + if (!token || !hasType(token, 'meta.tag-name') || iterator.stepBackward().value.match('/')) { + return + } + var element = token.value; + if (atCursor){ + var element = element.substring(0, position.column - token.start); + } + if (voidElements.indexOf(element) !== -1){ + return; + } + return { + text: '>' + '', + selection: [1, 1] + } + } + }); +} +oop.inherits(HtmlBehaviour, XmlBehaviour); + +exports.HtmlBehaviour = HtmlBehaviour; +}); diff --git a/lib/ace/mode/behaviour/xml.js b/lib/ace/mode/behaviour/xml.js new file mode 100644 index 0000000000..0d03b76364 --- /dev/null +++ b/lib/ace/mode/behaviour/xml.js @@ -0,0 +1,105 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../../lib/oop"); +var Behaviour = require("../behaviour").Behaviour; +var CstyleBehaviour = require("./cstyle").CstyleBehaviour; +var TokenIterator = require("../../token_iterator").TokenIterator; + +function hasType(token, type) { + var hasType = true; + var typeList = token.type.split('.'); + var needleList = type.split('.'); + needleList.forEach(function(needle){ + if (typeList.indexOf(needle) == -1) { + hasType = false; + return false; + } + }); + return hasType; +} + +var XmlBehaviour = function () { + + this.inherit(CstyleBehaviour, ["string_dquotes"]); // Get string behaviour + + this.add("autoclosing", "insertion", function (state, action, editor, session, text) { + if (text == '>') { + var position = editor.getCursorPosition(); + var iterator = new TokenIterator(session, position.row, position.column); + var token = iterator.getCurrentToken(); + var atCursor = false; + if (!token || !hasType(token, 'meta.tag') && !(hasType(token, 'text') && token.value.match('/'))){ + do { + token = iterator.stepBackward(); + } while (token && (hasType(token, 'string') || hasType(token, 'keyword.operator') || hasType(token, 'entity.attribute-name') || hasType(token, 'text'))); + } else { + atCursor = true; + } + if (!token || !hasType(token, 'meta.tag-name') || iterator.stepBackward().value.match('/')) { + return + } + var tag = token.value; + if (atCursor){ + var tag = tag.substring(0, position.column - token.start); + } + + return { + text: '>' + '', + selection: [1, 1] + } + } + }); + + this.add('autoindent', 'insertion', function (state, action, editor, session, text) { + if (text == "\n") { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + var rightChars = line.substring(cursor.column, cursor.column + 2); + if (rightChars == '. +*/ +define(function(require, exports, module) { +"use strict"; + + var oop = require("../../lib/oop"); + var Behaviour = require('../behaviour').Behaviour; + var CstyleBehaviour = require('./cstyle').CstyleBehaviour; + + var XQueryBehaviour = function (parent) { + + this.inherit(CstyleBehaviour, ["braces", "parens", "string_dquotes"]); // Get string behaviour + this.parent = parent; + +// this.add("brackets", "insertion", function (state, action, editor, session, text) { +// if (text == "\n") { +// var cursor = editor.getCursorPosition(); +// var line = session.doc.getLine(cursor.row); +// var rightChars = line.substring(cursor.column, cursor.column + 2); +// if (rightChars == ' 0 && line.charAt(cursor.column - 1) == "<") { +// line = line.substring(0, cursor.column) + "/" + line.substring(cursor.column); +// var lines = session.doc.getAllLines(); +// lines[cursor.row] = line; +// // call mode helper to close the tag if possible +// parent.exec("closeTag", lines.join(session.doc.getNewLineCharacter()), cursor.row); +// } +// } +// return false; +// }); + } + oop.inherits(XQueryBehaviour, Behaviour); + + exports.XQueryBehaviour = XQueryBehaviour; +}); diff --git a/lib/ace/mode/c9search.js b/lib/ace/mode/c9search.js new file mode 100644 index 0000000000..42342d28c9 --- /dev/null +++ b/lib/ace/mode/c9search.js @@ -0,0 +1,67 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var Tokenizer = require("../tokenizer").Tokenizer; +var C9SearchHighlightRules = require("./c9search_highlight_rules").C9SearchHighlightRules; +var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; +var C9StyleFoldMode = require("./folding/c9search").FoldMode; + +var Mode = function() { + this.$tokenizer = new Tokenizer(new C9SearchHighlightRules().getRules(), "i"); + this.$outdent = new MatchingBraceOutdent(); + this.foldingRules = new C9StyleFoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + + this.getNextLineIndent = function(state, line, tab) { + var indent = this.$getIndent(line); + return indent; + }; + + this.checkOutdent = function(state, line, input) { + return this.$outdent.checkOutdent(line, input); + }; + + this.autoOutdent = function(state, doc, row) { + this.$outdent.autoOutdent(doc, row); + }; + +}).call(Mode.prototype); + +exports.Mode = Mode; + +}); diff --git a/lib/ace/mode/c9search_highlight_rules.js b/lib/ace/mode/c9search_highlight_rules.js new file mode 100644 index 0000000000..df31112b32 --- /dev/null +++ b/lib/ace/mode/c9search_highlight_rules.js @@ -0,0 +1,59 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var C9SearchHighlightRules = function() { + + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + this.$rules = { + "start" : [ + { + token : ["c9searchresults.constant.numeric", "c9searchresults.text", "c9searchresults.text"], + regex : "(^\\s+[0-9]+)(:\\s*)(.+)" + }, + { + token : ["string", "text"], // single line + regex : "(.+)(:$)" + } + ] + }; +}; + +oop.inherits(C9SearchHighlightRules, TextHighlightRules); + +exports.C9SearchHighlightRules = C9SearchHighlightRules; + +}); diff --git a/lib/ace/mode/c_cpp.js b/lib/ace/mode/c_cpp.js new file mode 100644 index 0000000000..0776ef9755 --- /dev/null +++ b/lib/ace/mode/c_cpp.js @@ -0,0 +1,124 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var Tokenizer = require("../tokenizer").Tokenizer; +var c_cppHighlightRules = require("./c_cpp_highlight_rules").c_cppHighlightRules; +var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; +var Range = require("../range").Range; +var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour; +var CStyleFoldMode = require("./folding/cstyle").FoldMode; + +var Mode = function() { + this.$tokenizer = new Tokenizer(new c_cppHighlightRules().getRules()); + this.$outdent = new MatchingBraceOutdent(); + this.$behaviour = new CstyleBehaviour(); + this.foldingRules = new CStyleFoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + + this.toggleCommentLines = function(state, doc, startRow, endRow) { + var outdent = true; + var re = /^(\s*)\/\//; + + for (var i=startRow; i<= endRow; i++) { + if (!re.test(doc.getLine(i))) { + outdent = false; + break; + } + } + + if (outdent) { + var deleteRange = new Range(0, 0, 0, 0); + for (var i=startRow; i<= endRow; i++) + { + var line = doc.getLine(i); + var m = line.match(re); + deleteRange.start.row = i; + deleteRange.end.row = i; + deleteRange.end.column = m[0].length; + doc.replace(deleteRange, m[1]); + } + } + else { + doc.indentRows(startRow, endRow, "//"); + } + }; + + this.getNextLineIndent = function(state, line, tab) { + var indent = this.$getIndent(line); + + var tokenizedLine = this.$tokenizer.getLineTokens(line, state); + var tokens = tokenizedLine.tokens; + var endState = tokenizedLine.state; + + if (tokens.length && tokens[tokens.length-1].type == "comment") { + return indent; + } + + if (state == "start") { + var match = line.match(/^.*[\{\(\[]\s*$/); + if (match) { + indent += tab; + } + } else if (state == "doc-start") { + if (endState == "start") { + return ""; + } + var match = line.match(/^\s*(\/?)\*/); + if (match) { + if (match[1]) { + indent += " "; + } + indent += "* "; + } + } + + return indent; + }; + + this.checkOutdent = function(state, line, input) { + return this.$outdent.checkOutdent(line, input); + }; + + this.autoOutdent = function(state, doc, row) { + this.$outdent.autoOutdent(doc, row); + }; + +}).call(Mode.prototype); + +exports.Mode = Mode; +}); diff --git a/lib/ace/mode/c_cpp_highlight_rules.js b/lib/ace/mode/c_cpp_highlight_rules.js new file mode 100644 index 0000000000..9d57e46cb0 --- /dev/null +++ b/lib/ace/mode/c_cpp_highlight_rules.js @@ -0,0 +1,187 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var DocCommentHighlightRules = require("./doc_comment_highlight_rules").DocCommentHighlightRules; +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +// used by objective-c +var cFunctions = exports.cFunctions = "\\s*\\bhypot(?:f|l)?|s(?:scanf|ystem|nprintf|ca(?:nf|lb(?:n(?:f|l)?|ln(?:f|l)?))|i(?:n(?:h(?:f|l)?|f|l)?|gn(?:al|bit))|tr(?:s(?:tr|pn)|nc(?:py|at|mp)|c(?:spn|hr|oll|py|at|mp)|to(?:imax|d|u(?:l(?:l)?|max)|k|f|l(?:d|l)?)|error|pbrk|ftime|len|rchr|xfrm)|printf|et(?:jmp|vbuf|locale|buf)|qrt(?:f|l)?|w(?:scanf|printf)|rand)|n(?:e(?:arbyint(?:f|l)?|xt(?:toward(?:f|l)?|after(?:f|l)?))|an(?:f|l)?)|c(?:s(?:in(?:h(?:f|l)?|f|l)?|qrt(?:f|l)?)|cos(?:h(?:f)?|f|l)?|imag(?:f|l)?|t(?:ime|an(?:h(?:f|l)?|f|l)?)|o(?:s(?:h(?:f|l)?|f|l)?|nj(?:f|l)?|pysign(?:f|l)?)|p(?:ow(?:f|l)?|roj(?:f|l)?)|e(?:il(?:f|l)?|xp(?:f|l)?)|l(?:o(?:ck|g(?:f|l)?)|earerr)|a(?:sin(?:h(?:f|l)?|f|l)?|cos(?:h(?:f|l)?|f|l)?|tan(?:h(?:f|l)?|f|l)?|lloc|rg(?:f|l)?|bs(?:f|l)?)|real(?:f|l)?|brt(?:f|l)?)|t(?:ime|o(?:upper|lower)|an(?:h(?:f|l)?|f|l)?|runc(?:f|l)?|gamma(?:f|l)?|mp(?:nam|file))|i(?:s(?:space|n(?:ormal|an)|cntrl|inf|digit|u(?:nordered|pper)|p(?:unct|rint)|finite|w(?:space|c(?:ntrl|type)|digit|upper|p(?:unct|rint)|lower|al(?:num|pha)|graph|xdigit|blank)|l(?:ower|ess(?:equal|greater)?)|al(?:num|pha)|gr(?:eater(?:equal)?|aph)|xdigit|blank)|logb(?:f|l)?|max(?:div|abs))|di(?:v|fftime)|_Exit|unget(?:c|wc)|p(?:ow(?:f|l)?|ut(?:s|c(?:har)?|wc(?:har)?)|error|rintf)|e(?:rf(?:c(?:f|l)?|f|l)?|x(?:it|p(?:2(?:f|l)?|f|l|m1(?:f|l)?)?))|v(?:s(?:scanf|nprintf|canf|printf|w(?:scanf|printf))|printf|f(?:scanf|printf|w(?:scanf|printf))|w(?:scanf|printf)|a_(?:start|copy|end|arg))|qsort|f(?:s(?:canf|e(?:tpos|ek))|close|tell|open|dim(?:f|l)?|p(?:classify|ut(?:s|c|w(?:s|c))|rintf)|e(?:holdexcept|set(?:e(?:nv|xceptflag)|round)|clearexcept|testexcept|of|updateenv|r(?:aiseexcept|ror)|get(?:e(?:nv|xceptflag)|round))|flush|w(?:scanf|ide|printf|rite)|loor(?:f|l)?|abs(?:f|l)?|get(?:s|c|pos|w(?:s|c))|re(?:open|e|ad|xp(?:f|l)?)|m(?:in(?:f|l)?|od(?:f|l)?|a(?:f|l|x(?:f|l)?)?))|l(?:d(?:iv|exp(?:f|l)?)|o(?:ngjmp|cal(?:time|econv)|g(?:1(?:p(?:f|l)?|0(?:f|l)?)|2(?:f|l)?|f|l|b(?:f|l)?)?)|abs|l(?:div|abs|r(?:int(?:f|l)?|ound(?:f|l)?))|r(?:int(?:f|l)?|ound(?:f|l)?)|gamma(?:f|l)?)|w(?:scanf|c(?:s(?:s(?:tr|pn)|nc(?:py|at|mp)|c(?:spn|hr|oll|py|at|mp)|to(?:imax|d|u(?:l(?:l)?|max)|k|f|l(?:d|l)?|mbs)|pbrk|ftime|len|r(?:chr|tombs)|xfrm)|to(?:b|mb)|rtomb)|printf|mem(?:set|c(?:hr|py|mp)|move))|a(?:s(?:sert|ctime|in(?:h(?:f|l)?|f|l)?)|cos(?:h(?:f|l)?|f|l)?|t(?:o(?:i|f|l(?:l)?)|exit|an(?:h(?:f|l)?|2(?:f|l)?|f|l)?)|b(?:s|ort))|g(?:et(?:s|c(?:har)?|env|wc(?:har)?)|mtime)|r(?:int(?:f|l)?|ound(?:f|l)?|e(?:name|alloc|wind|m(?:ove|quo(?:f|l)?|ainder(?:f|l)?))|a(?:nd|ise))|b(?:search|towc)|m(?:odf(?:f|l)?|em(?:set|c(?:hr|py|mp)|move)|ktime|alloc|b(?:s(?:init|towcs|rtowcs)|towc|len|r(?:towc|len)))\\b" + +var c_cppHighlightRules = function() { + + var keywordControls = ( + "break|case|continue|default|do|else|for|goto|if|_Pragma|" + + "return|switch|while|catch|operator|try|throw|using" + ); + + var storageType = ( + "asm|__asm__|auto|bool|_Bool|char|_Complex|double|enum|float|" + + "_Imaginary|int|long|short|signed|struct|typedef|union|unsigned|void|" + + "class|wchar_t|template" + ); + + var storageModifiers = ( + "const|extern|register|restrict|static|volatile|inline|private:|" + + "protected:|public:|friend|explicit|virtual|export|mutable|typename" + ); + + var keywordOperators = ( + "and|and_eq|bitand|bitor|compl|not|not_eq|or|or_eq|typeid|xor|xor_eq" + + "const_cast|dynamic_cast|reinterpret_cast|static_cast|sizeof|namespace" + ); + + var builtinConstants = ( + "NULL|true|false|TRUE|FALSE" + ); + + var keywordMapper = exports.keywordMapper = this.createKeywordMapper({ + "keyword.control" : keywordControls, + "storage.type" : storageType, + "storage.modifier" : storageModifiers, + "keyword.operator" : keywordOperators, + "variable.language": "this", + "constant.language": builtinConstants + }, "identifier"); + + var identifierRe = "[a-zA-Z\\$_\u00a1-\uffff][a-zA-Z\d\\$_\u00a1-\uffff]*\\b"; + + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + + this.$rules = { + "start" : [ + { + token : "comment", + regex : "\\/\\/.*$" + }, + DocCommentHighlightRules.getStartRule("doc-start"), + { + token : "comment", // multi line comment + merge : true, + regex : "\\/\\*", + next : "comment" + }, { + token : "string", // single line + regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]' + }, { + token : "string", // multi line string start + merge : true, + regex : '["].*\\\\$', + next : "qqstring" + }, { + token : "string", // single line + regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']" + }, { + token : "string", // multi line string start + merge : true, + regex : "['].*\\\\$", + next : "qstring" + }, { + token : "constant.numeric", // hex + regex : "0[xX][0-9a-fA-F]+\\b" + }, { + token : "constant.numeric", // float + regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b" + }, { + token : "constant", // + regex : "<[a-zA-Z0-9.]+>" + }, { + token : "keyword", // pre-compiler directivs + regex : "(?:#include|#import|#pragma|#line|#define|#undef|#ifdef|#else|#elif|#endif|#ifndef)" + }, { + token : "support.function.C99.c", + regex : cFunctions + }, { + token : keywordMapper, + regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" + }, { + token : "keyword.operator", + regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|==|=|!=|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|new|delete|typeof|void)" + }, { + token : "punctuation.operator", + regex : "\\?|\\:|\\,|\\;|\\." + }, { + token : "paren.lparen", + regex : "[[({]" + }, { + token : "paren.rparen", + regex : "[\\])}]" + }, { + token : "text", + regex : "\\s+" + } + ], + "comment" : [ + { + token : "comment", // closing comment + regex : ".*?\\*\\/", + next : "start" + }, { + token : "comment", // comment spanning whole line + merge : true, + regex : ".+" + } + ], + "qqstring" : [ + { + token : "string", + regex : '(?:(?:\\\\.)|(?:[^"\\\\]))*?"', + next : "start" + }, { + token : "string", + merge : true, + regex : '.+' + } + ], + "qstring" : [ + { + token : "string", + regex : "(?:(?:\\\\.)|(?:[^'\\\\]))*?'", + next : "start" + }, { + token : "string", + merge : true, + regex : '.+' + } + ] + }; + + this.embedRules(DocCommentHighlightRules, "doc-", + [ DocCommentHighlightRules.getEndRule("start") ]); +}; + +oop.inherits(c_cppHighlightRules, TextHighlightRules); + +exports.c_cppHighlightRules = c_cppHighlightRules; +}); diff --git a/lib/ace/mode/clojure.js b/lib/ace/mode/clojure.js new file mode 100644 index 0000000000..581350b06a --- /dev/null +++ b/lib/ace/mode/clojure.js @@ -0,0 +1,112 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var Tokenizer = require("../tokenizer").Tokenizer; +var ClojureHighlightRules = require("./clojure_highlight_rules").ClojureHighlightRules; +var MatchingParensOutdent = require("./matching_parens_outdent").MatchingParensOutdent; +var Range = require("../range").Range; + +var Mode = function() { + this.$tokenizer = new Tokenizer(new ClojureHighlightRules().getRules()); + this.$outdent = new MatchingParensOutdent(); +}; +oop.inherits(Mode, TextMode); + +(function() { + + this.toggleCommentLines = function(state, doc, startRow, endRow) { + var outdent = true; + var re = /^(\s*)#/; + + for (var i=startRow; i<= endRow; i++) { + if (!re.test(doc.getLine(i))) { + outdent = false; + break; + } + } + + if (outdent) { + var deleteRange = new Range(0, 0, 0, 0); + for (var i=startRow; i<= endRow; i++) + { + var line = doc.getLine(i); + var m = line.match(re); + deleteRange.start.row = i; + deleteRange.end.row = i; + deleteRange.end.column = m[0].length; + doc.replace(deleteRange, m[1]); + } + } + else { + doc.indentRows(startRow, endRow, ";"); + } + }; + + this.getNextLineIndent = function(state, line, tab) { + var indent = this.$getIndent(line); + + var tokenizedLine = this.$tokenizer.getLineTokens(line, state); + var tokens = tokenizedLine.tokens; + + if (tokens.length && tokens[tokens.length-1].type == "comment") { + return indent; + } + + if (state == "start") { + var match = line.match(/[\(\[]/); + if (match) { + indent += " "; + } + match = line.match(/[\)]/); + if (match) { + indent = ""; + } + } + + return indent; + }; + + this.checkOutdent = function(state, line, input) { + return this.$outdent.checkOutdent(line, input); + }; + + this.autoOutdent = function(state, doc, row) { + this.$outdent.autoOutdent(doc, row); + }; + +}).call(Mode.prototype); + +exports.Mode = Mode; +}); diff --git a/lib/ace/mode/clojure_highlight_rules.js b/lib/ace/mode/clojure_highlight_rules.js new file mode 100644 index 0000000000..9890ededc6 --- /dev/null +++ b/lib/ace/mode/clojure_highlight_rules.js @@ -0,0 +1,219 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + + + +var ClojureHighlightRules = function() { + + var builtinFunctions = ( + '* *1 *2 *3 *agent* *allow-unresolved-vars* *assert* *clojure-version* ' + + '*command-line-args* *compile-files* *compile-path* *e *err* *file* ' + + '*flush-on-newline* *in* *macro-meta* *math-context* *ns* *out* ' + + '*print-dup* *print-length* *print-level* *print-meta* *print-readably* ' + + '*read-eval* *source-path* *use-context-classloader* ' + + '*warn-on-reflection* + - -> ->> .. / < <= = ' + + '== > > >= >= accessor aclone ' + + 'add-classpath add-watch agent agent-errors aget alength alias all-ns ' + + 'alter alter-meta! alter-var-root amap ancestors and apply areduce ' + + 'array-map aset aset-boolean aset-byte aset-char aset-double aset-float ' + + 'aset-int aset-long aset-short assert assoc assoc! assoc-in associative? ' + + 'atom await await-for await1 bases bean bigdec bigint binding bit-and ' + + 'bit-and-not bit-clear bit-flip bit-not bit-or bit-set bit-shift-left ' + + 'bit-shift-right bit-test bit-xor boolean boolean-array booleans ' + + 'bound-fn bound-fn* butlast byte byte-array bytes cast char char-array ' + + 'char-escape-string char-name-string char? chars chunk chunk-append ' + + 'chunk-buffer chunk-cons chunk-first chunk-next chunk-rest chunked-seq? ' + + 'class class? clear-agent-errors clojure-version coll? comment commute ' + + 'comp comparator compare compare-and-set! compile complement concat cond ' + + 'condp conj conj! cons constantly construct-proxy contains? count ' + + 'counted? create-ns create-struct cycle dec decimal? declare definline ' + + 'defmacro defmethod defmulti defn defn- defonce defstruct delay delay? ' + + 'deliver deref derive descendants destructure disj disj! dissoc dissoc! ' + + 'distinct distinct? doall doc dorun doseq dosync dotimes doto double ' + + 'double-array doubles drop drop-last drop-while empty empty? ensure ' + + 'enumeration-seq eval even? every? false? ffirst file-seq filter find ' + + 'find-doc find-ns find-var first float float-array float? floats flush ' + + 'fn fn? fnext for force format future future-call future-cancel ' + + 'future-cancelled? future-done? future? gen-class gen-interface gensym ' + + 'get get-in get-method get-proxy-class get-thread-bindings get-validator ' + + 'hash hash-map hash-set identical? identity if-let if-not ifn? import ' + + 'in-ns inc init-proxy instance? int int-array integer? interleave intern ' + + 'interpose into into-array ints io! isa? iterate iterator-seq juxt key ' + + 'keys keyword keyword? last lazy-cat lazy-seq let letfn line-seq list ' + + 'list* list? load load-file load-reader load-string loaded-libs locking ' + + 'long long-array longs loop macroexpand macroexpand-1 make-array ' + + 'make-hierarchy map map? mapcat max max-key memfn memoize merge ' + + 'merge-with meta method-sig methods min min-key mod name namespace neg? ' + + 'newline next nfirst nil? nnext not not-any? not-empty not-every? not= ' + + 'ns ns-aliases ns-imports ns-interns ns-map ns-name ns-publics ' + + 'ns-refers ns-resolve ns-unalias ns-unmap nth nthnext num number? odd? ' + + 'or parents partial partition pcalls peek persistent! pmap pop pop! ' + + 'pop-thread-bindings pos? pr pr-str prefer-method prefers ' + + 'primitives-classnames print print-ctor print-doc print-dup print-method ' + + 'print-namespace-doc print-simple print-special-doc print-str printf ' + + 'println println-str prn prn-str promise proxy proxy-call-with-super ' + + 'proxy-mappings proxy-name proxy-super push-thread-bindings pvalues quot ' + + 'rand rand-int range ratio? rational? rationalize re-find re-groups ' + + 're-matcher re-matches re-pattern re-seq read read-line read-string ' + + 'reduce ref ref-history-count ref-max-history ref-min-history ref-set ' + + 'refer refer-clojure release-pending-sends rem remove remove-method ' + + 'remove-ns remove-watch repeat repeatedly replace replicate require ' + + 'reset! reset-meta! resolve rest resultset-seq reverse reversible? rseq ' + + 'rsubseq second select-keys send send-off seq seq? seque sequence ' + + 'sequential? set set-validator! set? short short-array shorts ' + + 'shutdown-agents slurp some sort sort-by sorted-map sorted-map-by ' + + 'sorted-set sorted-set-by sorted? special-form-anchor special-symbol? ' + + 'split-at split-with str stream? string? struct struct-map subs subseq ' + + 'subvec supers swap! symbol symbol? sync syntax-symbol-anchor take ' + + 'take-last take-nth take-while test the-ns time to-array to-array-2d ' + + 'trampoline transient tree-seq true? type unchecked-add unchecked-dec ' + + 'unchecked-divide unchecked-inc unchecked-multiply unchecked-negate ' + + 'unchecked-remainder unchecked-subtract underive unquote ' + + 'unquote-splicing update-in update-proxy use val vals var-get var-set ' + + 'var? vary-meta vec vector vector? when when-first when-let when-not ' + + 'while with-bindings with-bindings* with-in-str with-loading-context ' + + 'with-local-vars with-meta with-open with-out-str with-precision xml-seq ' + + 'zero? zipmap' + ); + + var keywords = ('throw try var ' + + 'def do fn if let loop monitor-enter monitor-exit new quote recur set!' + ); + + var buildinConstants = ("true false nil"); + + var keywordMapper = this.createKeywordMapper({ + "keyword": keywords, + "constant.language": buildinConstants, + "support.function": builtinFunctions + }, "identifier", false, " "); + + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + + this.$rules = { + "start" : [ + { + token : "comment", + regex : ";.*$" + }, { + token : "comment", // multi line comment + regex : "^=begin$", + next : "comment" + }, { + token : "keyword", //parens + regex : "[\\(|\\)]" + }, { + token : "keyword", //lists + regex : "[\\'\\(]" + }, { + token : "keyword", //vectors + regex : "[\\[|\\]]" + }, { + token : "keyword", //sets and maps + regex : "[\\{|\\}|\\#\\{|\\#\\}]" + }, { + token : "keyword", // ampersands + regex : '[\\&]' + }, { + token : "keyword", // metadata + regex : '[\\#\\^\\{]' + }, { + token : "keyword", // anonymous fn syntactic sugar + regex : '[\\%]' + }, { + token : "keyword", // deref reader macro + regex : '[@]' + }, { + token : "constant.numeric", // hex + regex : "0[xX][0-9a-fA-F]+\\b" + }, { + token : "constant.numeric", // float + regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b" + }, { + token : "constant.language", + regex : '[!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+||=|!=|<=|>=|<>|<|>|!|&&]' + }, { + token : keywordMapper, + // TODO: Unicode escape sequences + // TODO: Unicode identifiers + regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" + }, { + token : "string", // single line + regex : '"', + next: "string" + }, { + token : "string", // symbol + regex : "[:](?:[a-zA-Z]|\\d)+" + }, { + token : "string.regexp", //Regular Expressions + regex : '/#"(?:\\.|(?:\\\")|[^\""\n])*"/g' + } + + ], + "comment" : [ + { + token : "comment", // closing comment + regex : "^=end$", + next : "start" + }, { + token : "comment", // comment spanning whole line + merge : true, + regex : ".+" + } + ], + "string" : [ + { + token : "constant.language.escape", + merge : true, + regex : "\\\\.|\\\\$" + }, { + token : "string", + merge : true, + regex : '[^"\\\\]+' + }, { + token : "string", + regex : '"', + next : "start" + } + ] + }; +}; + +oop.inherits(ClojureHighlightRules, TextHighlightRules); + +exports.ClojureHighlightRules = ClojureHighlightRules; +}); diff --git a/lib/ace/mode/coffee.js b/lib/ace/mode/coffee.js new file mode 100644 index 0000000000..85b1e9184b --- /dev/null +++ b/lib/ace/mode/coffee.js @@ -0,0 +1,114 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var Tokenizer = require("../tokenizer").Tokenizer; +var Rules = require("./coffee_highlight_rules").CoffeeHighlightRules; +var Outdent = require("./matching_brace_outdent").MatchingBraceOutdent; +var FoldMode = require("./folding/coffee").FoldMode; +var Range = require("../range").Range; +var TextMode = require("./text").Mode; +var WorkerClient = require("../worker/worker_client").WorkerClient; +var oop = require("../lib/oop"); + +function Mode() { + this.$tokenizer = new Tokenizer(new Rules().getRules()); + this.$outdent = new Outdent(); + this.foldingRules = new FoldMode(); +} + +oop.inherits(Mode, TextMode); + +(function() { + + var indenter = /(?:[({[=:]|[-=]>|\b(?:else|switch|try|catch(?:\s*[$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*)?|finally))\s*$/; + var commentLine = /^(\s*)#/; + var hereComment = /^\s*###(?!#)/; + var indentation = /^\s*/; + + this.getNextLineIndent = function(state, line, tab) { + var indent = this.$getIndent(line); + var tokens = this.$tokenizer.getLineTokens(line, state).tokens; + + if (!(tokens.length && tokens[tokens.length - 1].type === 'comment') && + state === 'start' && indenter.test(line)) + indent += tab; + return indent; + }; + + this.toggleCommentLines = function(state, doc, startRow, endRow){ + console.log("toggle"); + var range = new Range(0, 0, 0, 0); + for (var i = startRow; i <= endRow; ++i) { + var line = doc.getLine(i); + if (hereComment.test(line)) + continue; + + if (commentLine.test(line)) + line = line.replace(commentLine, '$1'); + else + line = line.replace(indentation, '$&#'); + + range.end.row = range.start.row = i; + range.end.column = line.length + 1; + doc.replace(range, line); + } + }; + + this.checkOutdent = function(state, line, input) { + return this.$outdent.checkOutdent(line, input); + }; + + this.autoOutdent = function(state, doc, row) { + this.$outdent.autoOutdent(doc, row); + }; + + this.createWorker = function(session) { + var worker = new WorkerClient(["ace"], "ace/mode/coffee_worker", "Worker"); + worker.attachToDocument(session.getDocument()); + + worker.on("error", function(e) { + session.setAnnotations([e.data]); + }); + + worker.on("ok", function(e) { + session.clearAnnotations(); + }); + + return worker; + }; + +}).call(Mode.prototype); + +exports.Mode = Mode; + +}); diff --git a/lib/ace/mode/coffee/coffee-script.js b/lib/ace/mode/coffee/coffee-script.js new file mode 100644 index 0000000000..1b7ae57ff3 --- /dev/null +++ b/lib/ace/mode/coffee/coffee-script.js @@ -0,0 +1,56 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + + var Lexer = require("./lexer").Lexer; + var parser = require("./parser"); + + var lexer = new Lexer(); + parser.lexer = { + lex: function() { + var tag, _ref2; + _ref2 = this.tokens[this.pos++] || [''], tag = _ref2[0], this.yytext = _ref2[1], this.yylineno = _ref2[2]; + return tag; + }, + setInput: function(tokens) { + this.tokens = tokens; + return this.pos = 0; + }, + upcomingInput: function() { + return ""; + } + }; + parser.yy = require('./nodes'); + + exports.parse = function(code) { + return parser.parse(lexer.tokenize(code)); + }; +}); diff --git a/lib/ace/mode/coffee/helpers.js b/lib/ace/mode/coffee/helpers.js new file mode 100644 index 0000000000..88473f547d --- /dev/null +++ b/lib/ace/mode/coffee/helpers.js @@ -0,0 +1,115 @@ +/** + * Copyright (c) 2009-2012 Jeremy Ashkenas + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +define(function(require, exports, module) { +// Generated by CoffeeScript 1.3.3 + + var extend, flatten, _ref; + + exports.starts = function(string, literal, start) { + return literal === string.substr(start, literal.length); + }; + + exports.ends = function(string, literal, back) { + var len; + len = literal.length; + return literal === string.substr(string.length - len - (back || 0), len); + }; + + exports.compact = function(array) { + var item, _i, _len, _results; + _results = []; + for (_i = 0, _len = array.length; _i < _len; _i++) { + item = array[_i]; + if (item) { + _results.push(item); + } + } + return _results; + }; + + exports.count = function(string, substr) { + var num, pos; + num = pos = 0; + if (!substr.length) { + return 1 / 0; + } + while (pos = 1 + string.indexOf(substr, pos)) { + num++; + } + return num; + }; + + exports.merge = function(options, overrides) { + return extend(extend({}, options), overrides); + }; + + extend = exports.extend = function(object, properties) { + var key, val; + for (key in properties) { + val = properties[key]; + object[key] = val; + } + return object; + }; + + exports.flatten = flatten = function(array) { + var element, flattened, _i, _len; + flattened = []; + for (_i = 0, _len = array.length; _i < _len; _i++) { + element = array[_i]; + if (element instanceof Array) { + flattened = flattened.concat(flatten(element)); + } else { + flattened.push(element); + } + } + return flattened; + }; + + exports.del = function(obj, key) { + var val; + val = obj[key]; + delete obj[key]; + return val; + }; + + exports.last = function(array, back) { + return array[array.length - (back || 0) - 1]; + }; + + exports.some = (_ref = Array.prototype.some) != null ? _ref : function(fn) { + var e, _i, _len; + for (_i = 0, _len = this.length; _i < _len; _i++) { + e = this[_i]; + if (fn(e)) { + return true; + } + } + return false; + }; + + +}); \ No newline at end of file diff --git a/lib/ace/mode/coffee/lexer.js b/lib/ace/mode/coffee/lexer.js new file mode 100644 index 0000000000..ec661c287f --- /dev/null +++ b/lib/ace/mode/coffee/lexer.js @@ -0,0 +1,815 @@ +/** + * Copyright (c) 2009-2012 Jeremy Ashkenas + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +define(function(require, exports, module) { +// Generated by CoffeeScript 1.3.3 + + var BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HEREDOC, HEREDOC_ILLEGAL, HEREDOC_INDENT, HEREGEX, HEREGEX_OMIT, IDENTIFIER, INDEXABLE, INVERSES, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LINE_BREAK, LINE_CONTINUER, LOGIC, Lexer, MATH, MULTILINER, MULTI_DENT, NOT_REGEX, NOT_SPACED_REGEX, NUMBER, OPERATOR, REGEX, RELATION, RESERVED, Rewriter, SHIFT, SIMPLESTR, STRICT_PROSCRIBED, TRAILING_SPACES, UNARY, WHITESPACE, compact, count, key, last, starts, _ref, _ref1, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + + _ref = require('./rewriter'), Rewriter = _ref.Rewriter, INVERSES = _ref.INVERSES; + + _ref1 = require('./helpers'), count = _ref1.count, starts = _ref1.starts, compact = _ref1.compact, last = _ref1.last; + + exports.Lexer = Lexer = (function() { + + function Lexer() {} + + Lexer.prototype.tokenize = function(code, opts) { + var i, tag; + if (opts == null) { + opts = {}; + } + if (WHITESPACE.test(code)) { + code = "\n" + code; + } + code = code.replace(/\r/g, '').replace(TRAILING_SPACES, ''); + this.code = code; + this.line = opts.line || 0; + this.indent = 0; + this.indebt = 0; + this.outdebt = 0; + this.indents = []; + this.ends = []; + this.tokens = []; + i = 0; + while (this.chunk = code.slice(i)) { + i += this.identifierToken() || this.commentToken() || this.whitespaceToken() || this.lineToken() || this.heredocToken() || this.stringToken() || this.numberToken() || this.regexToken() || this.jsToken() || this.literalToken(); + } + this.closeIndentation(); + if (tag = this.ends.pop()) { + this.error("missing " + tag); + } + if (opts.rewrite === false) { + return this.tokens; + } + return (new Rewriter).rewrite(this.tokens); + }; + + Lexer.prototype.identifierToken = function() { + var colon, forcedIdentifier, id, input, match, prev, tag, _ref2, _ref3; + if (!(match = IDENTIFIER.exec(this.chunk))) { + return 0; + } + input = match[0], id = match[1], colon = match[2]; + if (id === 'own' && this.tag() === 'FOR') { + this.token('OWN', id); + return id.length; + } + forcedIdentifier = colon || (prev = last(this.tokens)) && (((_ref2 = prev[0]) === '.' || _ref2 === '?.' || _ref2 === '::') || !prev.spaced && prev[0] === '@'); + tag = 'IDENTIFIER'; + if (!forcedIdentifier && (__indexOf.call(JS_KEYWORDS, id) >= 0 || __indexOf.call(COFFEE_KEYWORDS, id) >= 0)) { + tag = id.toUpperCase(); + if (tag === 'WHEN' && (_ref3 = this.tag(), __indexOf.call(LINE_BREAK, _ref3) >= 0)) { + tag = 'LEADING_WHEN'; + } else if (tag === 'FOR') { + this.seenFor = true; + } else if (tag === 'UNLESS') { + tag = 'IF'; + } else if (__indexOf.call(UNARY, tag) >= 0) { + tag = 'UNARY'; + } else if (__indexOf.call(RELATION, tag) >= 0) { + if (tag !== 'INSTANCEOF' && this.seenFor) { + tag = 'FOR' + tag; + this.seenFor = false; + } else { + tag = 'RELATION'; + if (this.value() === '!') { + this.tokens.pop(); + id = '!' + id; + } + } + } + } + if (__indexOf.call(JS_FORBIDDEN, id) >= 0) { + if (forcedIdentifier) { + tag = 'IDENTIFIER'; + id = new String(id); + id.reserved = true; + } else if (__indexOf.call(RESERVED, id) >= 0) { + this.error("reserved word \"" + id + "\""); + } + } + if (!forcedIdentifier) { + if (__indexOf.call(COFFEE_ALIASES, id) >= 0) { + id = COFFEE_ALIAS_MAP[id]; + } + tag = (function() { + switch (id) { + case '!': + return 'UNARY'; + case '==': + case '!=': + return 'COMPARE'; + case '&&': + case '||': + return 'LOGIC'; + case 'true': + case 'false': + return 'BOOL'; + case 'break': + case 'continue': + return 'STATEMENT'; + default: + return tag; + } + })(); + } + this.token(tag, id); + if (colon) { + this.token(':', ':'); + } + return input.length; + }; + + Lexer.prototype.numberToken = function() { + var binaryLiteral, lexedLength, match, number, octalLiteral; + if (!(match = NUMBER.exec(this.chunk))) { + return 0; + } + number = match[0]; + if (/^0[BOX]/.test(number)) { + this.error("radix prefix '" + number + "' must be lowercase"); + } else if (/E/.test(number) && !/^0x/.test(number)) { + this.error("exponential notation '" + number + "' must be indicated with a lowercase 'e'"); + } else if (/^0\d*[89]/.test(number)) { + this.error("decimal literal '" + number + "' must not be prefixed with '0'"); + } else if (/^0\d+/.test(number)) { + this.error("octal literal '" + number + "' must be prefixed with '0o'"); + } + lexedLength = number.length; + if (octalLiteral = /^0o([0-7]+)/.exec(number)) { + number = '0x' + (parseInt(octalLiteral[1], 8)).toString(16); + } + if (binaryLiteral = /^0b([01]+)/.exec(number)) { + number = '0x' + (parseInt(binaryLiteral[1], 2)).toString(16); + } + this.token('NUMBER', number); + return lexedLength; + }; + + Lexer.prototype.stringToken = function() { + var match, octalEsc, string; + switch (this.chunk.charAt(0)) { + case "'": + if (!(match = SIMPLESTR.exec(this.chunk))) { + return 0; + } + this.token('STRING', (string = match[0]).replace(MULTILINER, '\\\n')); + break; + case '"': + if (!(string = this.balancedString(this.chunk, '"'))) { + return 0; + } + if (0 < string.indexOf('#{', 1)) { + this.interpolateString(string.slice(1, -1)); + } else { + this.token('STRING', this.escapeLines(string)); + } + break; + default: + return 0; + } + if (octalEsc = /^(?:\\.|[^\\])*\\(?:0[0-7]|[1-7])/.test(string)) { + this.error("octal escape sequences " + string + " are not allowed"); + } + this.line += count(string, '\n'); + return string.length; + }; + + Lexer.prototype.heredocToken = function() { + var doc, heredoc, match, quote; + if (!(match = HEREDOC.exec(this.chunk))) { + return 0; + } + heredoc = match[0]; + quote = heredoc.charAt(0); + doc = this.sanitizeHeredoc(match[2], { + quote: quote, + indent: null + }); + if (quote === '"' && 0 <= doc.indexOf('#{')) { + this.interpolateString(doc, { + heredoc: true + }); + } else { + this.token('STRING', this.makeString(doc, quote, true)); + } + this.line += count(heredoc, '\n'); + return heredoc.length; + }; + + Lexer.prototype.commentToken = function() { + var comment, here, match; + if (!(match = this.chunk.match(COMMENT))) { + return 0; + } + comment = match[0], here = match[1]; + if (here) { + this.token('HERECOMMENT', this.sanitizeHeredoc(here, { + herecomment: true, + indent: Array(this.indent + 1).join(' ') + })); + } + this.line += count(comment, '\n'); + return comment.length; + }; + + Lexer.prototype.jsToken = function() { + var match, script; + if (!(this.chunk.charAt(0) === '`' && (match = JSTOKEN.exec(this.chunk)))) { + return 0; + } + this.token('JS', (script = match[0]).slice(1, -1)); + this.line += count(script, '\n'); + return script.length; + }; + + Lexer.prototype.regexToken = function() { + var flags, length, match, prev, regex, _ref2, _ref3; + if (this.chunk.charAt(0) !== '/') { + return 0; + } + if (match = HEREGEX.exec(this.chunk)) { + length = this.heregexToken(match); + this.line += count(match[0], '\n'); + return length; + } + prev = last(this.tokens); + if (prev && (_ref2 = prev[0], __indexOf.call((prev.spaced ? NOT_REGEX : NOT_SPACED_REGEX), _ref2) >= 0)) { + return 0; + } + if (!(match = REGEX.exec(this.chunk))) { + return 0; + } + _ref3 = match, match = _ref3[0], regex = _ref3[1], flags = _ref3[2]; + if (regex.slice(0, 2) === '/*') { + this.error('regular expressions cannot begin with `*`'); + } + if (regex === '//') { + regex = '/(?:)/'; + } + this.token('REGEX', "" + regex + flags); + return match.length; + }; + + Lexer.prototype.heregexToken = function(match) { + var body, flags, heregex, re, tag, tokens, value, _i, _len, _ref2, _ref3, _ref4, _ref5; + heregex = match[0], body = match[1], flags = match[2]; + if (0 > body.indexOf('#{')) { + re = body.replace(HEREGEX_OMIT, '').replace(/\//g, '\\/'); + if (re.match(/^\*/)) { + this.error('regular expressions cannot begin with `*`'); + } + this.token('REGEX', "/" + (re || '(?:)') + "/" + flags); + return heregex.length; + } + this.token('IDENTIFIER', 'RegExp'); + this.tokens.push(['CALL_START', '(']); + tokens = []; + _ref2 = this.interpolateString(body, { + regex: true + }); + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + _ref3 = _ref2[_i], tag = _ref3[0], value = _ref3[1]; + if (tag === 'TOKENS') { + tokens.push.apply(tokens, value); + } else { + if (!(value = value.replace(HEREGEX_OMIT, ''))) { + continue; + } + value = value.replace(/\\/g, '\\\\'); + tokens.push(['STRING', this.makeString(value, '"', true)]); + } + tokens.push(['+', '+']); + } + tokens.pop(); + if (((_ref4 = tokens[0]) != null ? _ref4[0] : void 0) !== 'STRING') { + this.tokens.push(['STRING', '""'], ['+', '+']); + } + (_ref5 = this.tokens).push.apply(_ref5, tokens); + if (flags) { + this.tokens.push([',', ','], ['STRING', '"' + flags + '"']); + } + this.token(')', ')'); + return heregex.length; + }; + + Lexer.prototype.lineToken = function() { + var diff, indent, match, noNewlines, size; + if (!(match = MULTI_DENT.exec(this.chunk))) { + return 0; + } + indent = match[0]; + this.line += count(indent, '\n'); + this.seenFor = false; + size = indent.length - 1 - indent.lastIndexOf('\n'); + noNewlines = this.unfinished(); + if (size - this.indebt === this.indent) { + if (noNewlines) { + this.suppressNewlines(); + } else { + this.newlineToken(); + } + return indent.length; + } + if (size > this.indent) { + if (noNewlines) { + this.indebt = size - this.indent; + this.suppressNewlines(); + return indent.length; + } + diff = size - this.indent + this.outdebt; + this.token('INDENT', diff); + this.indents.push(diff); + this.ends.push('OUTDENT'); + this.outdebt = this.indebt = 0; + } else { + this.indebt = 0; + this.outdentToken(this.indent - size, noNewlines); + } + this.indent = size; + return indent.length; + }; + + Lexer.prototype.outdentToken = function(moveOut, noNewlines) { + var dent, len; + while (moveOut > 0) { + len = this.indents.length - 1; + if (this.indents[len] === void 0) { + moveOut = 0; + } else if (this.indents[len] === this.outdebt) { + moveOut -= this.outdebt; + this.outdebt = 0; + } else if (this.indents[len] < this.outdebt) { + this.outdebt -= this.indents[len]; + moveOut -= this.indents[len]; + } else { + dent = this.indents.pop() - this.outdebt; + moveOut -= dent; + this.outdebt = 0; + this.pair('OUTDENT'); + this.token('OUTDENT', dent); + } + } + if (dent) { + this.outdebt -= moveOut; + } + while (this.value() === ';') { + this.tokens.pop(); + } + if (!(this.tag() === 'TERMINATOR' || noNewlines)) { + this.token('TERMINATOR', '\n'); + } + return this; + }; + + Lexer.prototype.whitespaceToken = function() { + var match, nline, prev; + if (!((match = WHITESPACE.exec(this.chunk)) || (nline = this.chunk.charAt(0) === '\n'))) { + return 0; + } + prev = last(this.tokens); + if (prev) { + prev[match ? 'spaced' : 'newLine'] = true; + } + if (match) { + return match[0].length; + } else { + return 0; + } + }; + + Lexer.prototype.newlineToken = function() { + while (this.value() === ';') { + this.tokens.pop(); + } + if (this.tag() !== 'TERMINATOR') { + this.token('TERMINATOR', '\n'); + } + return this; + }; + + Lexer.prototype.suppressNewlines = function() { + if (this.value() === '\\') { + this.tokens.pop(); + } + return this; + }; + + Lexer.prototype.literalToken = function() { + var match, prev, tag, value, _ref2, _ref3, _ref4, _ref5; + if (match = OPERATOR.exec(this.chunk)) { + value = match[0]; + if (CODE.test(value)) { + this.tagParameters(); + } + } else { + value = this.chunk.charAt(0); + } + tag = value; + prev = last(this.tokens); + if (value === '=' && prev) { + if (!prev[1].reserved && (_ref2 = prev[1], __indexOf.call(JS_FORBIDDEN, _ref2) >= 0)) { + this.error("reserved word \"" + (this.value()) + "\" can't be assigned"); + } + if ((_ref3 = prev[1]) === '||' || _ref3 === '&&') { + prev[0] = 'COMPOUND_ASSIGN'; + prev[1] += '='; + return value.length; + } + } + if (value === ';') { + this.seenFor = false; + tag = 'TERMINATOR'; + } else if (__indexOf.call(MATH, value) >= 0) { + tag = 'MATH'; + } else if (__indexOf.call(COMPARE, value) >= 0) { + tag = 'COMPARE'; + } else if (__indexOf.call(COMPOUND_ASSIGN, value) >= 0) { + tag = 'COMPOUND_ASSIGN'; + } else if (__indexOf.call(UNARY, value) >= 0) { + tag = 'UNARY'; + } else if (__indexOf.call(SHIFT, value) >= 0) { + tag = 'SHIFT'; + } else if (__indexOf.call(LOGIC, value) >= 0 || value === '?' && (prev != null ? prev.spaced : void 0)) { + tag = 'LOGIC'; + } else if (prev && !prev.spaced) { + if (value === '(' && (_ref4 = prev[0], __indexOf.call(CALLABLE, _ref4) >= 0)) { + if (prev[0] === '?') { + prev[0] = 'FUNC_EXIST'; + } + tag = 'CALL_START'; + } else if (value === '[' && (_ref5 = prev[0], __indexOf.call(INDEXABLE, _ref5) >= 0)) { + tag = 'INDEX_START'; + switch (prev[0]) { + case '?': + prev[0] = 'INDEX_SOAK'; + } + } + } + switch (value) { + case '(': + case '{': + case '[': + this.ends.push(INVERSES[value]); + break; + case ')': + case '}': + case ']': + this.pair(value); + } + this.token(tag, value); + return value.length; + }; + + Lexer.prototype.sanitizeHeredoc = function(doc, options) { + var attempt, herecomment, indent, match, _ref2; + indent = options.indent, herecomment = options.herecomment; + if (herecomment) { + if (HEREDOC_ILLEGAL.test(doc)) { + this.error("block comment cannot contain \"*/\", starting"); + } + if (doc.indexOf('\n') <= 0) { + return doc; + } + } else { + while (match = HEREDOC_INDENT.exec(doc)) { + attempt = match[1]; + if (indent === null || (0 < (_ref2 = attempt.length) && _ref2 < indent.length)) { + indent = attempt; + } + } + } + if (indent) { + doc = doc.replace(RegExp("\\n" + indent, "g"), '\n'); + } + if (!herecomment) { + doc = doc.replace(/^\n/, ''); + } + return doc; + }; + + Lexer.prototype.tagParameters = function() { + var i, stack, tok, tokens; + if (this.tag() !== ')') { + return this; + } + stack = []; + tokens = this.tokens; + i = tokens.length; + tokens[--i][0] = 'PARAM_END'; + while (tok = tokens[--i]) { + switch (tok[0]) { + case ')': + stack.push(tok); + break; + case '(': + case 'CALL_START': + if (stack.length) { + stack.pop(); + } else if (tok[0] === '(') { + tok[0] = 'PARAM_START'; + return this; + } else { + return this; + } + } + } + return this; + }; + + Lexer.prototype.closeIndentation = function() { + return this.outdentToken(this.indent); + }; + + Lexer.prototype.balancedString = function(str, end) { + var continueCount, i, letter, match, prev, stack, _i, _ref2; + continueCount = 0; + stack = [end]; + for (i = _i = 1, _ref2 = str.length; 1 <= _ref2 ? _i < _ref2 : _i > _ref2; i = 1 <= _ref2 ? ++_i : --_i) { + if (continueCount) { + --continueCount; + continue; + } + switch (letter = str.charAt(i)) { + case '\\': + ++continueCount; + continue; + case end: + stack.pop(); + if (!stack.length) { + return str.slice(0, +i + 1 || 9e9); + } + end = stack[stack.length - 1]; + continue; + } + if (end === '}' && (letter === '"' || letter === "'")) { + stack.push(end = letter); + } else if (end === '}' && letter === '/' && (match = HEREGEX.exec(str.slice(i)) || REGEX.exec(str.slice(i)))) { + continueCount += match[0].length - 1; + } else if (end === '}' && letter === '{') { + stack.push(end = '}'); + } else if (end === '"' && prev === '#' && letter === '{') { + stack.push(end = '}'); + } + prev = letter; + } + return this.error("missing " + (stack.pop()) + ", starting"); + }; + + Lexer.prototype.interpolateString = function(str, options) { + var expr, heredoc, i, inner, interpolated, len, letter, nested, pi, regex, tag, tokens, value, _i, _len, _ref2, _ref3, _ref4; + if (options == null) { + options = {}; + } + heredoc = options.heredoc, regex = options.regex; + tokens = []; + pi = 0; + i = -1; + while (letter = str.charAt(i += 1)) { + if (letter === '\\') { + i += 1; + continue; + } + if (!(letter === '#' && str.charAt(i + 1) === '{' && (expr = this.balancedString(str.slice(i + 1), '}')))) { + continue; + } + if (pi < i) { + tokens.push(['NEOSTRING', str.slice(pi, i)]); + } + inner = expr.slice(1, -1); + if (inner.length) { + nested = new Lexer().tokenize(inner, { + line: this.line, + rewrite: false + }); + nested.pop(); + if (((_ref2 = nested[0]) != null ? _ref2[0] : void 0) === 'TERMINATOR') { + nested.shift(); + } + if (len = nested.length) { + if (len > 1) { + nested.unshift(['(', '(', this.line]); + nested.push([')', ')', this.line]); + } + tokens.push(['TOKENS', nested]); + } + } + i += expr.length; + pi = i + 1; + } + if ((i > pi && pi < str.length)) { + tokens.push(['NEOSTRING', str.slice(pi)]); + } + if (regex) { + return tokens; + } + if (!tokens.length) { + return this.token('STRING', '""'); + } + if (tokens[0][0] !== 'NEOSTRING') { + tokens.unshift(['', '']); + } + if (interpolated = tokens.length > 1) { + this.token('(', '('); + } + for (i = _i = 0, _len = tokens.length; _i < _len; i = ++_i) { + _ref3 = tokens[i], tag = _ref3[0], value = _ref3[1]; + if (i) { + this.token('+', '+'); + } + if (tag === 'TOKENS') { + (_ref4 = this.tokens).push.apply(_ref4, value); + } else { + this.token('STRING', this.makeString(value, '"', heredoc)); + } + } + if (interpolated) { + this.token(')', ')'); + } + return tokens; + }; + + Lexer.prototype.pair = function(tag) { + var size, wanted; + if (tag !== (wanted = last(this.ends))) { + if ('OUTDENT' !== wanted) { + this.error("unmatched " + tag); + } + this.indent -= size = last(this.indents); + this.outdentToken(size, true); + return this.pair(tag); + } + return this.ends.pop(); + }; + + Lexer.prototype.token = function(tag, value) { + return this.tokens.push([tag, value, this.line]); + }; + + Lexer.prototype.tag = function(index, tag) { + var tok; + return (tok = last(this.tokens, index)) && (tag ? tok[0] = tag : tok[0]); + }; + + Lexer.prototype.value = function(index, val) { + var tok; + return (tok = last(this.tokens, index)) && (val ? tok[1] = val : tok[1]); + }; + + Lexer.prototype.unfinished = function() { + var _ref2; + return LINE_CONTINUER.test(this.chunk) || ((_ref2 = this.tag()) === '\\' || _ref2 === '.' || _ref2 === '?.' || _ref2 === 'UNARY' || _ref2 === 'MATH' || _ref2 === '+' || _ref2 === '-' || _ref2 === 'SHIFT' || _ref2 === 'RELATION' || _ref2 === 'COMPARE' || _ref2 === 'LOGIC' || _ref2 === 'THROW' || _ref2 === 'EXTENDS'); + }; + + Lexer.prototype.escapeLines = function(str, heredoc) { + return str.replace(MULTILINER, heredoc ? '\\n' : ''); + }; + + Lexer.prototype.makeString = function(body, quote, heredoc) { + if (!body) { + return quote + quote; + } + body = body.replace(/\\([\s\S])/g, function(match, contents) { + if (contents === '\n' || contents === quote) { + return contents; + } else { + return match; + } + }); + body = body.replace(RegExp("" + quote, "g"), '\\$&'); + return quote + this.escapeLines(body, heredoc) + quote; + }; + + Lexer.prototype.error = function(message) { + throw SyntaxError("" + message + " on line " + (this.line + 1)); + }; + + return Lexer; + + })(); + + JS_KEYWORDS = ['true', 'false', 'null', 'this', 'new', 'delete', 'typeof', 'in', 'instanceof', 'return', 'throw', 'break', 'continue', 'debugger', 'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally', 'class', 'extends', 'super']; + + COFFEE_KEYWORDS = ['undefined', 'then', 'unless', 'until', 'loop', 'of', 'by', 'when']; + + COFFEE_ALIAS_MAP = { + and: '&&', + or: '||', + is: '==', + isnt: '!=', + not: '!', + yes: 'true', + no: 'false', + on: 'true', + off: 'false' + }; + + COFFEE_ALIASES = (function() { + var _results; + _results = []; + for (key in COFFEE_ALIAS_MAP) { + _results.push(key); + } + return _results; + })(); + + COFFEE_KEYWORDS = COFFEE_KEYWORDS.concat(COFFEE_ALIASES); + + RESERVED = ['case', 'default', 'function', 'var', 'void', 'with', 'const', 'let', 'enum', 'export', 'import', 'native', '__hasProp', '__extends', '__slice', '__bind', '__indexOf', 'implements', 'interface', 'package', 'private', 'protected', 'public', 'static', 'yield']; + + STRICT_PROSCRIBED = ['arguments', 'eval']; + + JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED).concat(STRICT_PROSCRIBED); + + exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS).concat(STRICT_PROSCRIBED); + + exports.STRICT_PROSCRIBED = STRICT_PROSCRIBED; + + IDENTIFIER = /^([$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*)([^\n\S]*:(?!:))?/; + + NUMBER = /^0b[01]+|^0o[0-7]+|^0x[\da-f]+|^\d*\.?\d+(?:e[+-]?\d+)?/i; + + HEREDOC = /^("""|''')([\s\S]*?)(?:\n[^\n\S]*)?\1/; + + OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/; + + WHITESPACE = /^[^\n\S]+/; + + COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/; + + CODE = /^[-=]>/; + + MULTI_DENT = /^(?:\n[^\n\S]*)+/; + + SIMPLESTR = /^'[^\\']*(?:\\.[^\\']*)*'/; + + JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/; + + REGEX = /^(\/(?![\s=])[^[\/\n\\]*(?:(?:\\[\s\S]|\[[^\]\n\\]*(?:\\[\s\S][^\]\n\\]*)*])[^[\/\n\\]*)*\/)([imgy]{0,4})(?!\w)/; + + HEREGEX = /^\/{3}([\s\S]+?)\/{3}([imgy]{0,4})(?!\w)/; + + HEREGEX_OMIT = /\s+(?:#.*)?/g; + + MULTILINER = /\n/g; + + HEREDOC_INDENT = /\n+([^\n\S]*)/g; + + HEREDOC_ILLEGAL = /\*\//; + + LINE_CONTINUER = /^\s*(?:,|\??\.(?![.\d])|::)/; + + TRAILING_SPACES = /\s+$/; + + COMPOUND_ASSIGN = ['-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|=']; + + UNARY = ['!', '~', 'NEW', 'TYPEOF', 'DELETE', 'DO']; + + LOGIC = ['&&', '||', '&', '|', '^']; + + SHIFT = ['<<', '>>', '>>>']; + + COMPARE = ['==', '!=', '<', '>', '<=', '>=']; + + MATH = ['*', '/', '%']; + + RELATION = ['IN', 'OF', 'INSTANCEOF']; + + BOOL = ['TRUE', 'FALSE']; + + NOT_REGEX = ['NUMBER', 'REGEX', 'BOOL', 'NULL', 'UNDEFINED', '++', '--', ']']; + + NOT_SPACED_REGEX = NOT_REGEX.concat(')', '}', 'THIS', 'IDENTIFIER', 'STRING'); + + CALLABLE = ['IDENTIFIER', 'STRING', 'REGEX', ')', ']', '}', '?', '::', '@', 'THIS', 'SUPER']; + + INDEXABLE = CALLABLE.concat('NUMBER', 'BOOL', 'NULL', 'UNDEFINED'); + + LINE_BREAK = ['INDENT', 'OUTDENT', 'TERMINATOR']; + + +}); \ No newline at end of file diff --git a/lib/ace/mode/coffee/nodes.js b/lib/ace/mode/coffee/nodes.js new file mode 100644 index 0000000000..6808bf4ef4 --- /dev/null +++ b/lib/ace/mode/coffee/nodes.js @@ -0,0 +1,2998 @@ +/** + * Copyright (c) 2009-2012 Jeremy Ashkenas + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +define(function(require, exports, module) { +// Generated by CoffeeScript 1.3.3 + + var Access, Arr, Assign, Base, Block, Call, Class, Closure, Code, Comment, Existence, Extends, For, IDENTIFIER, IDENTIFIER_STR, IS_STRING, If, In, Index, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, METHOD_DEF, NEGATE, NO, Obj, Op, Param, Parens, RESERVED, Range, Return, SIMPLENUM, STRICT_PROSCRIBED, Scope, Slice, Splat, Switch, TAB, THIS, Throw, Try, UTILITIES, Value, While, YES, compact, del, ends, extend, flatten, last, merge, multident, some, starts, unfoldSoak, utility, _ref, _ref1, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + + Scope = require('./scope').Scope; + + _ref = require('./lexer'), RESERVED = _ref.RESERVED, STRICT_PROSCRIBED = _ref.STRICT_PROSCRIBED; + + _ref1 = require('./helpers'), compact = _ref1.compact, flatten = _ref1.flatten, extend = _ref1.extend, merge = _ref1.merge, del = _ref1.del, starts = _ref1.starts, ends = _ref1.ends, last = _ref1.last, some = _ref1.some; + + exports.extend = extend; + + YES = function() { + return true; + }; + + NO = function() { + return false; + }; + + THIS = function() { + return this; + }; + + NEGATE = function() { + this.negated = !this.negated; + return this; + }; + + exports.Base = Base = (function() { + + function Base() {} + + Base.prototype.compile = function(o, lvl) { + var node; + o = extend({}, o); + if (lvl) { + o.level = lvl; + } + node = this.unfoldSoak(o) || this; + node.tab = o.indent; + if (o.level === LEVEL_TOP || !node.isStatement(o)) { + return node.compileNode(o); + } else { + return node.compileClosure(o); + } + }; + + Base.prototype.compileClosure = function(o) { + if (this.jumps()) { + throw SyntaxError('cannot use a pure statement in an expression.'); + } + o.sharedScope = true; + return Closure.wrap(this).compileNode(o); + }; + + Base.prototype.cache = function(o, level, reused) { + var ref, sub; + if (!this.isComplex()) { + ref = level ? this.compile(o, level) : this; + return [ref, ref]; + } else { + ref = new Literal(reused || o.scope.freeVariable('ref')); + sub = new Assign(ref, this); + if (level) { + return [sub.compile(o, level), ref.value]; + } else { + return [sub, ref]; + } + } + }; + + Base.prototype.compileLoopReference = function(o, name) { + var src, tmp; + src = tmp = this.compile(o, LEVEL_LIST); + if (!((-Infinity < +src && +src < Infinity) || IDENTIFIER.test(src) && o.scope.check(src, true))) { + src = "" + (tmp = o.scope.freeVariable(name)) + " = " + src; + } + return [src, tmp]; + }; + + Base.prototype.makeReturn = function(res) { + var me; + me = this.unwrapAll(); + if (res) { + return new Call(new Literal("" + res + ".push"), [me]); + } else { + return new Return(me); + } + }; + + Base.prototype.contains = function(pred) { + var contains; + contains = false; + this.traverseChildren(false, function(node) { + if (pred(node)) { + contains = true; + return false; + } + }); + return contains; + }; + + Base.prototype.containsType = function(type) { + return this instanceof type || this.contains(function(node) { + return node instanceof type; + }); + }; + + Base.prototype.lastNonComment = function(list) { + var i; + i = list.length; + while (i--) { + if (!(list[i] instanceof Comment)) { + return list[i]; + } + } + return null; + }; + + Base.prototype.toString = function(idt, name) { + var tree; + if (idt == null) { + idt = ''; + } + if (name == null) { + name = this.constructor.name; + } + tree = '\n' + idt + name; + if (this.soak) { + tree += '?'; + } + this.eachChild(function(node) { + return tree += node.toString(idt + TAB); + }); + return tree; + }; + + Base.prototype.eachChild = function(func) { + var attr, child, _i, _j, _len, _len1, _ref2, _ref3; + if (!this.children) { + return this; + } + _ref2 = this.children; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + attr = _ref2[_i]; + if (this[attr]) { + _ref3 = flatten([this[attr]]); + for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) { + child = _ref3[_j]; + if (func(child) === false) { + return this; + } + } + } + } + return this; + }; + + Base.prototype.traverseChildren = function(crossScope, func) { + return this.eachChild(function(child) { + if (func(child) === false) { + return false; + } + return child.traverseChildren(crossScope, func); + }); + }; + + Base.prototype.invert = function() { + return new Op('!', this); + }; + + Base.prototype.unwrapAll = function() { + var node; + node = this; + while (node !== (node = node.unwrap())) { + continue; + } + return node; + }; + + Base.prototype.children = []; + + Base.prototype.isStatement = NO; + + Base.prototype.jumps = NO; + + Base.prototype.isComplex = YES; + + Base.prototype.isChainable = NO; + + Base.prototype.isAssignable = NO; + + Base.prototype.unwrap = THIS; + + Base.prototype.unfoldSoak = NO; + + Base.prototype.assigns = NO; + + return Base; + + })(); + + exports.Block = Block = (function(_super) { + + __extends(Block, _super); + + function Block(nodes) { + this.expressions = compact(flatten(nodes || [])); + } + + Block.prototype.children = ['expressions']; + + Block.prototype.push = function(node) { + this.expressions.push(node); + return this; + }; + + Block.prototype.pop = function() { + return this.expressions.pop(); + }; + + Block.prototype.unshift = function(node) { + this.expressions.unshift(node); + return this; + }; + + Block.prototype.unwrap = function() { + if (this.expressions.length === 1) { + return this.expressions[0]; + } else { + return this; + } + }; + + Block.prototype.isEmpty = function() { + return !this.expressions.length; + }; + + Block.prototype.isStatement = function(o) { + var exp, _i, _len, _ref2; + _ref2 = this.expressions; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + exp = _ref2[_i]; + if (exp.isStatement(o)) { + return true; + } + } + return false; + }; + + Block.prototype.jumps = function(o) { + var exp, _i, _len, _ref2; + _ref2 = this.expressions; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + exp = _ref2[_i]; + if (exp.jumps(o)) { + return exp; + } + } + }; + + Block.prototype.makeReturn = function(res) { + var expr, len; + len = this.expressions.length; + while (len--) { + expr = this.expressions[len]; + if (!(expr instanceof Comment)) { + this.expressions[len] = expr.makeReturn(res); + if (expr instanceof Return && !expr.expression) { + this.expressions.splice(len, 1); + } + break; + } + } + return this; + }; + + Block.prototype.compile = function(o, level) { + if (o == null) { + o = {}; + } + if (o.scope) { + return Block.__super__.compile.call(this, o, level); + } else { + return this.compileRoot(o); + } + }; + + Block.prototype.compileNode = function(o) { + var code, codes, node, top, _i, _len, _ref2; + this.tab = o.indent; + top = o.level === LEVEL_TOP; + codes = []; + _ref2 = this.expressions; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + node = _ref2[_i]; + node = node.unwrapAll(); + node = node.unfoldSoak(o) || node; + if (node instanceof Block) { + codes.push(node.compileNode(o)); + } else if (top) { + node.front = true; + code = node.compile(o); + if (!node.isStatement(o)) { + code = "" + this.tab + code + ";"; + if (node instanceof Literal) { + code = "" + code + "\n"; + } + } + codes.push(code); + } else { + codes.push(node.compile(o, LEVEL_LIST)); + } + } + if (top) { + if (this.spaced) { + return "\n" + (codes.join('\n\n')) + "\n"; + } else { + return codes.join('\n'); + } + } + code = codes.join(', ') || 'void 0'; + if (codes.length > 1 && o.level >= LEVEL_LIST) { + return "(" + code + ")"; + } else { + return code; + } + }; + + Block.prototype.compileRoot = function(o) { + var code, exp, i, prelude, preludeExps, rest; + o.indent = o.bare ? '' : TAB; + o.scope = new Scope(null, this, null); + o.level = LEVEL_TOP; + this.spaced = true; + prelude = ""; + if (!o.bare) { + preludeExps = (function() { + var _i, _len, _ref2, _results; + _ref2 = this.expressions; + _results = []; + for (i = _i = 0, _len = _ref2.length; _i < _len; i = ++_i) { + exp = _ref2[i]; + if (!(exp.unwrap() instanceof Comment)) { + break; + } + _results.push(exp); + } + return _results; + }).call(this); + rest = this.expressions.slice(preludeExps.length); + this.expressions = preludeExps; + if (preludeExps.length) { + prelude = "" + (this.compileNode(merge(o, { + indent: '' + }))) + "\n"; + } + this.expressions = rest; + } + code = this.compileWithDeclarations(o); + if (o.bare) { + return code; + } + return "" + prelude + "(function() {\n" + code + "\n}).call(this);\n"; + }; + + Block.prototype.compileWithDeclarations = function(o) { + var assigns, code, declars, exp, i, post, rest, scope, spaced, _i, _len, _ref2, _ref3, _ref4; + code = post = ''; + _ref2 = this.expressions; + for (i = _i = 0, _len = _ref2.length; _i < _len; i = ++_i) { + exp = _ref2[i]; + exp = exp.unwrap(); + if (!(exp instanceof Comment || exp instanceof Literal)) { + break; + } + } + o = merge(o, { + level: LEVEL_TOP + }); + if (i) { + rest = this.expressions.splice(i, 9e9); + _ref3 = [this.spaced, false], spaced = _ref3[0], this.spaced = _ref3[1]; + _ref4 = [this.compileNode(o), spaced], code = _ref4[0], this.spaced = _ref4[1]; + this.expressions = rest; + } + post = this.compileNode(o); + scope = o.scope; + if (scope.expressions === this) { + declars = o.scope.hasDeclarations(); + assigns = scope.hasAssignments; + if (declars || assigns) { + if (i) { + code += '\n'; + } + code += "" + this.tab + "var "; + if (declars) { + code += scope.declaredVariables().join(', '); + } + if (assigns) { + if (declars) { + code += ",\n" + (this.tab + TAB); + } + code += scope.assignedVariables().join(",\n" + (this.tab + TAB)); + } + code += ';\n'; + } + } + return code + post; + }; + + Block.wrap = function(nodes) { + if (nodes.length === 1 && nodes[0] instanceof Block) { + return nodes[0]; + } + return new Block(nodes); + }; + + return Block; + + })(Base); + + exports.Literal = Literal = (function(_super) { + + __extends(Literal, _super); + + function Literal(value) { + this.value = value; + } + + Literal.prototype.makeReturn = function() { + if (this.isStatement()) { + return this; + } else { + return Literal.__super__.makeReturn.apply(this, arguments); + } + }; + + Literal.prototype.isAssignable = function() { + return IDENTIFIER.test(this.value); + }; + + Literal.prototype.isStatement = function() { + var _ref2; + return (_ref2 = this.value) === 'break' || _ref2 === 'continue' || _ref2 === 'debugger'; + }; + + Literal.prototype.isComplex = NO; + + Literal.prototype.assigns = function(name) { + return name === this.value; + }; + + Literal.prototype.jumps = function(o) { + if (this.value === 'break' && !((o != null ? o.loop : void 0) || (o != null ? o.block : void 0))) { + return this; + } + if (this.value === 'continue' && !(o != null ? o.loop : void 0)) { + return this; + } + }; + + Literal.prototype.compileNode = function(o) { + var code, _ref2; + code = this.value === 'this' ? ((_ref2 = o.scope.method) != null ? _ref2.bound : void 0) ? o.scope.method.context : this.value : this.value.reserved ? "\"" + this.value + "\"" : this.value; + if (this.isStatement()) { + return "" + this.tab + code + ";"; + } else { + return code; + } + }; + + Literal.prototype.toString = function() { + return ' "' + this.value + '"'; + }; + + return Literal; + + })(Base); + + exports.Undefined = (function(_super) { + + __extends(Undefined, _super); + + function Undefined() { + return Undefined.__super__.constructor.apply(this, arguments); + } + + Undefined.prototype.isAssignable = NO; + + Undefined.prototype.isComplex = NO; + + Undefined.prototype.compileNode = function(o) { + if (o.level >= LEVEL_ACCESS) { + return '(void 0)'; + } else { + return 'void 0'; + } + }; + + return Undefined; + + })(Base); + + exports.Null = (function(_super) { + + __extends(Null, _super); + + function Null() { + return Null.__super__.constructor.apply(this, arguments); + } + + Null.prototype.isAssignable = NO; + + Null.prototype.isComplex = NO; + + Null.prototype.compileNode = function() { + return "null"; + }; + + return Null; + + })(Base); + + exports.Bool = (function(_super) { + + __extends(Bool, _super); + + Bool.prototype.isAssignable = NO; + + Bool.prototype.isComplex = NO; + + Bool.prototype.compileNode = function() { + return this.val; + }; + + function Bool(val) { + this.val = val; + } + + return Bool; + + })(Base); + + exports.Return = Return = (function(_super) { + + __extends(Return, _super); + + function Return(expr) { + if (expr && !expr.unwrap().isUndefined) { + this.expression = expr; + } + } + + Return.prototype.children = ['expression']; + + Return.prototype.isStatement = YES; + + Return.prototype.makeReturn = THIS; + + Return.prototype.jumps = THIS; + + Return.prototype.compile = function(o, level) { + var expr, _ref2; + expr = (_ref2 = this.expression) != null ? _ref2.makeReturn() : void 0; + if (expr && !(expr instanceof Return)) { + return expr.compile(o, level); + } else { + return Return.__super__.compile.call(this, o, level); + } + }; + + Return.prototype.compileNode = function(o) { + return this.tab + ("return" + [this.expression ? " " + (this.expression.compile(o, LEVEL_PAREN)) : void 0] + ";"); + }; + + return Return; + + })(Base); + + exports.Value = Value = (function(_super) { + + __extends(Value, _super); + + function Value(base, props, tag) { + if (!props && base instanceof Value) { + return base; + } + this.base = base; + this.properties = props || []; + if (tag) { + this[tag] = true; + } + return this; + } + + Value.prototype.children = ['base', 'properties']; + + Value.prototype.add = function(props) { + this.properties = this.properties.concat(props); + return this; + }; + + Value.prototype.hasProperties = function() { + return !!this.properties.length; + }; + + Value.prototype.isArray = function() { + return !this.properties.length && this.base instanceof Arr; + }; + + Value.prototype.isComplex = function() { + return this.hasProperties() || this.base.isComplex(); + }; + + Value.prototype.isAssignable = function() { + return this.hasProperties() || this.base.isAssignable(); + }; + + Value.prototype.isSimpleNumber = function() { + return this.base instanceof Literal && SIMPLENUM.test(this.base.value); + }; + + Value.prototype.isString = function() { + return this.base instanceof Literal && IS_STRING.test(this.base.value); + }; + + Value.prototype.isAtomic = function() { + var node, _i, _len, _ref2; + _ref2 = this.properties.concat(this.base); + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + node = _ref2[_i]; + if (node.soak || node instanceof Call) { + return false; + } + } + return true; + }; + + Value.prototype.isStatement = function(o) { + return !this.properties.length && this.base.isStatement(o); + }; + + Value.prototype.assigns = function(name) { + return !this.properties.length && this.base.assigns(name); + }; + + Value.prototype.jumps = function(o) { + return !this.properties.length && this.base.jumps(o); + }; + + Value.prototype.isObject = function(onlyGenerated) { + if (this.properties.length) { + return false; + } + return (this.base instanceof Obj) && (!onlyGenerated || this.base.generated); + }; + + Value.prototype.isSplice = function() { + return last(this.properties) instanceof Slice; + }; + + Value.prototype.unwrap = function() { + if (this.properties.length) { + return this; + } else { + return this.base; + } + }; + + Value.prototype.cacheReference = function(o) { + var base, bref, name, nref; + name = last(this.properties); + if (this.properties.length < 2 && !this.base.isComplex() && !(name != null ? name.isComplex() : void 0)) { + return [this, this]; + } + base = new Value(this.base, this.properties.slice(0, -1)); + if (base.isComplex()) { + bref = new Literal(o.scope.freeVariable('base')); + base = new Value(new Parens(new Assign(bref, base))); + } + if (!name) { + return [base, bref]; + } + if (name.isComplex()) { + nref = new Literal(o.scope.freeVariable('name')); + name = new Index(new Assign(nref, name.index)); + nref = new Index(nref); + } + return [base.add(name), new Value(bref || base.base, [nref || name])]; + }; + + Value.prototype.compileNode = function(o) { + var code, prop, props, _i, _len; + this.base.front = this.front; + props = this.properties; + code = this.base.compile(o, props.length ? LEVEL_ACCESS : null); + if ((this.base instanceof Parens || props.length) && SIMPLENUM.test(code)) { + code = "" + code + "."; + } + for (_i = 0, _len = props.length; _i < _len; _i++) { + prop = props[_i]; + code += prop.compile(o); + } + return code; + }; + + Value.prototype.unfoldSoak = function(o) { + var result, + _this = this; + if (this.unfoldedSoak != null) { + return this.unfoldedSoak; + } + result = (function() { + var fst, i, ifn, prop, ref, snd, _i, _len, _ref2; + if (ifn = _this.base.unfoldSoak(o)) { + Array.prototype.push.apply(ifn.body.properties, _this.properties); + return ifn; + } + _ref2 = _this.properties; + for (i = _i = 0, _len = _ref2.length; _i < _len; i = ++_i) { + prop = _ref2[i]; + if (!prop.soak) { + continue; + } + prop.soak = false; + fst = new Value(_this.base, _this.properties.slice(0, i)); + snd = new Value(_this.base, _this.properties.slice(i)); + if (fst.isComplex()) { + ref = new Literal(o.scope.freeVariable('ref')); + fst = new Parens(new Assign(ref, fst)); + snd.base = ref; + } + return new If(new Existence(fst), snd, { + soak: true + }); + } + return null; + })(); + return this.unfoldedSoak = result || false; + }; + + return Value; + + })(Base); + + exports.Comment = Comment = (function(_super) { + + __extends(Comment, _super); + + function Comment(comment) { + this.comment = comment; + } + + Comment.prototype.isStatement = YES; + + Comment.prototype.makeReturn = THIS; + + Comment.prototype.compileNode = function(o, level) { + var code; + code = '/*' + multident(this.comment, this.tab) + ("\n" + this.tab + "*/\n"); + if ((level || o.level) === LEVEL_TOP) { + code = o.indent + code; + } + return code; + }; + + return Comment; + + })(Base); + + exports.Call = Call = (function(_super) { + + __extends(Call, _super); + + function Call(variable, args, soak) { + this.args = args != null ? args : []; + this.soak = soak; + this.isNew = false; + this.isSuper = variable === 'super'; + this.variable = this.isSuper ? null : variable; + } + + Call.prototype.children = ['variable', 'args']; + + Call.prototype.newInstance = function() { + var base, _ref2; + base = ((_ref2 = this.variable) != null ? _ref2.base : void 0) || this.variable; + if (base instanceof Call && !base.isNew) { + base.newInstance(); + } else { + this.isNew = true; + } + return this; + }; + + Call.prototype.superReference = function(o) { + var accesses, method, name; + method = o.scope.namedMethod(); + if (!method) { + throw SyntaxError('cannot call super outside of a function.'); + } + name = method.name; + if (name == null) { + throw SyntaxError('cannot call super on an anonymous function.'); + } + if (method.klass) { + accesses = [new Access(new Literal('__super__'))]; + if (method["static"]) { + accesses.push(new Access(new Literal('constructor'))); + } + accesses.push(new Access(new Literal(name))); + return (new Value(new Literal(method.klass), accesses)).compile(o); + } else { + return "" + name + ".__super__.constructor"; + } + }; + + Call.prototype.superThis = function(o) { + var method; + method = o.scope.method; + return (method && !method.klass && method.context) || "this"; + }; + + Call.prototype.unfoldSoak = function(o) { + var call, ifn, left, list, rite, _i, _len, _ref2, _ref3; + if (this.soak) { + if (this.variable) { + if (ifn = unfoldSoak(o, this, 'variable')) { + return ifn; + } + _ref2 = new Value(this.variable).cacheReference(o), left = _ref2[0], rite = _ref2[1]; + } else { + left = new Literal(this.superReference(o)); + rite = new Value(left); + } + rite = new Call(rite, this.args); + rite.isNew = this.isNew; + left = new Literal("typeof " + (left.compile(o)) + " === \"function\""); + return new If(left, new Value(rite), { + soak: true + }); + } + call = this; + list = []; + while (true) { + if (call.variable instanceof Call) { + list.push(call); + call = call.variable; + continue; + } + if (!(call.variable instanceof Value)) { + break; + } + list.push(call); + if (!((call = call.variable.base) instanceof Call)) { + break; + } + } + _ref3 = list.reverse(); + for (_i = 0, _len = _ref3.length; _i < _len; _i++) { + call = _ref3[_i]; + if (ifn) { + if (call.variable instanceof Call) { + call.variable = ifn; + } else { + call.variable.base = ifn; + } + } + ifn = unfoldSoak(o, call, 'variable'); + } + return ifn; + }; + + Call.prototype.filterImplicitObjects = function(list) { + var node, nodes, obj, prop, properties, _i, _j, _len, _len1, _ref2; + nodes = []; + for (_i = 0, _len = list.length; _i < _len; _i++) { + node = list[_i]; + if (!((typeof node.isObject === "function" ? node.isObject() : void 0) && node.base.generated)) { + nodes.push(node); + continue; + } + obj = null; + _ref2 = node.base.properties; + for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) { + prop = _ref2[_j]; + if (prop instanceof Assign || prop instanceof Comment) { + if (!obj) { + nodes.push(obj = new Obj(properties = [], true)); + } + properties.push(prop); + } else { + nodes.push(prop); + obj = null; + } + } + } + return nodes; + }; + + Call.prototype.compileNode = function(o) { + var arg, args, code, _ref2; + if ((_ref2 = this.variable) != null) { + _ref2.front = this.front; + } + if (code = Splat.compileSplattedArray(o, this.args, true)) { + return this.compileSplat(o, code); + } + args = this.filterImplicitObjects(this.args); + args = ((function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = args.length; _i < _len; _i++) { + arg = args[_i]; + _results.push(arg.compile(o, LEVEL_LIST)); + } + return _results; + })()).join(', '); + if (this.isSuper) { + return this.superReference(o) + (".call(" + (this.superThis(o)) + (args && ', ' + args) + ")"); + } else { + return (this.isNew ? 'new ' : '') + this.variable.compile(o, LEVEL_ACCESS) + ("(" + args + ")"); + } + }; + + Call.prototype.compileSuper = function(args, o) { + return "" + (this.superReference(o)) + ".call(" + (this.superThis(o)) + (args.length ? ', ' : '') + args + ")"; + }; + + Call.prototype.compileSplat = function(o, splatArgs) { + var base, fun, idt, name, ref; + if (this.isSuper) { + return "" + (this.superReference(o)) + ".apply(" + (this.superThis(o)) + ", " + splatArgs + ")"; + } + if (this.isNew) { + idt = this.tab + TAB; + return "(function(func, args, ctor) {\n" + idt + "ctor.prototype = func.prototype;\n" + idt + "var child = new ctor, result = func.apply(child, args), t = typeof result;\n" + idt + "return t == \"object\" || t == \"function\" ? result || child : child;\n" + this.tab + "})(" + (this.variable.compile(o, LEVEL_LIST)) + ", " + splatArgs + ", function(){})"; + } + base = new Value(this.variable); + if ((name = base.properties.pop()) && base.isComplex()) { + ref = o.scope.freeVariable('ref'); + fun = "(" + ref + " = " + (base.compile(o, LEVEL_LIST)) + ")" + (name.compile(o)); + } else { + fun = base.compile(o, LEVEL_ACCESS); + if (SIMPLENUM.test(fun)) { + fun = "(" + fun + ")"; + } + if (name) { + ref = fun; + fun += name.compile(o); + } else { + ref = 'null'; + } + } + return "" + fun + ".apply(" + ref + ", " + splatArgs + ")"; + }; + + return Call; + + })(Base); + + exports.Extends = Extends = (function(_super) { + + __extends(Extends, _super); + + function Extends(child, parent) { + this.child = child; + this.parent = parent; + } + + Extends.prototype.children = ['child', 'parent']; + + Extends.prototype.compile = function(o) { + return new Call(new Value(new Literal(utility('extends'))), [this.child, this.parent]).compile(o); + }; + + return Extends; + + })(Base); + + exports.Access = Access = (function(_super) { + + __extends(Access, _super); + + function Access(name, tag) { + this.name = name; + this.name.asKey = true; + this.soak = tag === 'soak'; + } + + Access.prototype.children = ['name']; + + Access.prototype.compile = function(o) { + var name; + name = this.name.compile(o); + if (IDENTIFIER.test(name)) { + return "." + name; + } else { + return "[" + name + "]"; + } + }; + + Access.prototype.isComplex = NO; + + return Access; + + })(Base); + + exports.Index = Index = (function(_super) { + + __extends(Index, _super); + + function Index(index) { + this.index = index; + } + + Index.prototype.children = ['index']; + + Index.prototype.compile = function(o) { + return "[" + (this.index.compile(o, LEVEL_PAREN)) + "]"; + }; + + Index.prototype.isComplex = function() { + return this.index.isComplex(); + }; + + return Index; + + })(Base); + + exports.Range = Range = (function(_super) { + + __extends(Range, _super); + + Range.prototype.children = ['from', 'to']; + + function Range(from, to, tag) { + this.from = from; + this.to = to; + this.exclusive = tag === 'exclusive'; + this.equals = this.exclusive ? '' : '='; + } + + Range.prototype.compileVariables = function(o) { + var step, _ref2, _ref3, _ref4, _ref5; + o = merge(o, { + top: true + }); + _ref2 = this.from.cache(o, LEVEL_LIST), this.fromC = _ref2[0], this.fromVar = _ref2[1]; + _ref3 = this.to.cache(o, LEVEL_LIST), this.toC = _ref3[0], this.toVar = _ref3[1]; + if (step = del(o, 'step')) { + _ref4 = step.cache(o, LEVEL_LIST), this.step = _ref4[0], this.stepVar = _ref4[1]; + } + _ref5 = [this.fromVar.match(SIMPLENUM), this.toVar.match(SIMPLENUM)], this.fromNum = _ref5[0], this.toNum = _ref5[1]; + if (this.stepVar) { + return this.stepNum = this.stepVar.match(SIMPLENUM); + } + }; + + Range.prototype.compileNode = function(o) { + var cond, condPart, from, gt, idx, idxName, known, lt, namedIndex, stepPart, to, varPart, _ref2, _ref3; + if (!this.fromVar) { + this.compileVariables(o); + } + if (!o.index) { + return this.compileArray(o); + } + known = this.fromNum && this.toNum; + idx = del(o, 'index'); + idxName = del(o, 'name'); + namedIndex = idxName && idxName !== idx; + varPart = "" + idx + " = " + this.fromC; + if (this.toC !== this.toVar) { + varPart += ", " + this.toC; + } + if (this.step !== this.stepVar) { + varPart += ", " + this.step; + } + _ref2 = ["" + idx + " <" + this.equals, "" + idx + " >" + this.equals], lt = _ref2[0], gt = _ref2[1]; + condPart = this.stepNum ? +this.stepNum > 0 ? "" + lt + " " + this.toVar : "" + gt + " " + this.toVar : known ? ((_ref3 = [+this.fromNum, +this.toNum], from = _ref3[0], to = _ref3[1], _ref3), from <= to ? "" + lt + " " + to : "" + gt + " " + to) : (cond = "" + this.fromVar + " <= " + this.toVar, "" + cond + " ? " + lt + " " + this.toVar + " : " + gt + " " + this.toVar); + stepPart = this.stepVar ? "" + idx + " += " + this.stepVar : known ? namedIndex ? from <= to ? "++" + idx : "--" + idx : from <= to ? "" + idx + "++" : "" + idx + "--" : namedIndex ? "" + cond + " ? ++" + idx + " : --" + idx : "" + cond + " ? " + idx + "++ : " + idx + "--"; + if (namedIndex) { + varPart = "" + idxName + " = " + varPart; + } + if (namedIndex) { + stepPart = "" + idxName + " = " + stepPart; + } + return "" + varPart + "; " + condPart + "; " + stepPart; + }; + + Range.prototype.compileArray = function(o) { + var args, body, cond, hasArgs, i, idt, post, pre, range, result, vars, _i, _ref2, _ref3, _results; + if (this.fromNum && this.toNum && Math.abs(this.fromNum - this.toNum) <= 20) { + range = (function() { + _results = []; + for (var _i = _ref2 = +this.fromNum, _ref3 = +this.toNum; _ref2 <= _ref3 ? _i <= _ref3 : _i >= _ref3; _ref2 <= _ref3 ? _i++ : _i--){ _results.push(_i); } + return _results; + }).apply(this); + if (this.exclusive) { + range.pop(); + } + return "[" + (range.join(', ')) + "]"; + } + idt = this.tab + TAB; + i = o.scope.freeVariable('i'); + result = o.scope.freeVariable('results'); + pre = "\n" + idt + result + " = [];"; + if (this.fromNum && this.toNum) { + o.index = i; + body = this.compileNode(o); + } else { + vars = ("" + i + " = " + this.fromC) + (this.toC !== this.toVar ? ", " + this.toC : ''); + cond = "" + this.fromVar + " <= " + this.toVar; + body = "var " + vars + "; " + cond + " ? " + i + " <" + this.equals + " " + this.toVar + " : " + i + " >" + this.equals + " " + this.toVar + "; " + cond + " ? " + i + "++ : " + i + "--"; + } + post = "{ " + result + ".push(" + i + "); }\n" + idt + "return " + result + ";\n" + o.indent; + hasArgs = function(node) { + return node != null ? node.contains(function(n) { + return n instanceof Literal && n.value === 'arguments' && !n.asKey; + }) : void 0; + }; + if (hasArgs(this.from) || hasArgs(this.to)) { + args = ', arguments'; + } + return "(function() {" + pre + "\n" + idt + "for (" + body + ")" + post + "}).apply(this" + (args != null ? args : '') + ")"; + }; + + return Range; + + })(Base); + + exports.Slice = Slice = (function(_super) { + + __extends(Slice, _super); + + Slice.prototype.children = ['range']; + + function Slice(range) { + this.range = range; + Slice.__super__.constructor.call(this); + } + + Slice.prototype.compileNode = function(o) { + var compiled, from, fromStr, to, toStr, _ref2; + _ref2 = this.range, to = _ref2.to, from = _ref2.from; + fromStr = from && from.compile(o, LEVEL_PAREN) || '0'; + compiled = to && to.compile(o, LEVEL_PAREN); + if (to && !(!this.range.exclusive && +compiled === -1)) { + toStr = ', ' + (this.range.exclusive ? compiled : SIMPLENUM.test(compiled) ? "" + (+compiled + 1) : (compiled = to.compile(o, LEVEL_ACCESS), "+" + compiled + " + 1 || 9e9")); + } + return ".slice(" + fromStr + (toStr || '') + ")"; + }; + + return Slice; + + })(Base); + + exports.Obj = Obj = (function(_super) { + + __extends(Obj, _super); + + function Obj(props, generated) { + this.generated = generated != null ? generated : false; + this.objects = this.properties = props || []; + } + + Obj.prototype.children = ['properties']; + + Obj.prototype.compileNode = function(o) { + var i, idt, indent, join, lastNoncom, node, obj, prop, props, _i, _len; + props = this.properties; + if (!props.length) { + return (this.front ? '({})' : '{}'); + } + if (this.generated) { + for (_i = 0, _len = props.length; _i < _len; _i++) { + node = props[_i]; + if (node instanceof Value) { + throw new Error('cannot have an implicit value in an implicit object'); + } + } + } + idt = o.indent += TAB; + lastNoncom = this.lastNonComment(this.properties); + props = (function() { + var _j, _len1, _results; + _results = []; + for (i = _j = 0, _len1 = props.length; _j < _len1; i = ++_j) { + prop = props[i]; + join = i === props.length - 1 ? '' : prop === lastNoncom || prop instanceof Comment ? '\n' : ',\n'; + indent = prop instanceof Comment ? '' : idt; + if (prop instanceof Value && prop["this"]) { + prop = new Assign(prop.properties[0].name, prop, 'object'); + } + if (!(prop instanceof Comment)) { + if (!(prop instanceof Assign)) { + prop = new Assign(prop, prop, 'object'); + } + (prop.variable.base || prop.variable).asKey = true; + } + _results.push(indent + prop.compile(o, LEVEL_TOP) + join); + } + return _results; + })(); + props = props.join(''); + obj = "{" + (props && '\n' + props + '\n' + this.tab) + "}"; + if (this.front) { + return "(" + obj + ")"; + } else { + return obj; + } + }; + + Obj.prototype.assigns = function(name) { + var prop, _i, _len, _ref2; + _ref2 = this.properties; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + prop = _ref2[_i]; + if (prop.assigns(name)) { + return true; + } + } + return false; + }; + + return Obj; + + })(Base); + + exports.Arr = Arr = (function(_super) { + + __extends(Arr, _super); + + function Arr(objs) { + this.objects = objs || []; + } + + Arr.prototype.children = ['objects']; + + Arr.prototype.filterImplicitObjects = Call.prototype.filterImplicitObjects; + + Arr.prototype.compileNode = function(o) { + var code, obj, objs; + if (!this.objects.length) { + return '[]'; + } + o.indent += TAB; + objs = this.filterImplicitObjects(this.objects); + if (code = Splat.compileSplattedArray(o, objs)) { + return code; + } + code = ((function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = objs.length; _i < _len; _i++) { + obj = objs[_i]; + _results.push(obj.compile(o, LEVEL_LIST)); + } + return _results; + })()).join(', '); + if (code.indexOf('\n') >= 0) { + return "[\n" + o.indent + code + "\n" + this.tab + "]"; + } else { + return "[" + code + "]"; + } + }; + + Arr.prototype.assigns = function(name) { + var obj, _i, _len, _ref2; + _ref2 = this.objects; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + obj = _ref2[_i]; + if (obj.assigns(name)) { + return true; + } + } + return false; + }; + + return Arr; + + })(Base); + + exports.Class = Class = (function(_super) { + + __extends(Class, _super); + + function Class(variable, parent, body) { + this.variable = variable; + this.parent = parent; + this.body = body != null ? body : new Block; + this.boundFuncs = []; + this.body.classBody = true; + } + + Class.prototype.children = ['variable', 'parent', 'body']; + + Class.prototype.determineName = function() { + var decl, tail; + if (!this.variable) { + return null; + } + decl = (tail = last(this.variable.properties)) ? tail instanceof Access && tail.name.value : this.variable.base.value; + if (__indexOf.call(STRICT_PROSCRIBED, decl) >= 0) { + throw SyntaxError("variable name may not be " + decl); + } + return decl && (decl = IDENTIFIER.test(decl) && decl); + }; + + Class.prototype.setContext = function(name) { + return this.body.traverseChildren(false, function(node) { + if (node.classBody) { + return false; + } + if (node instanceof Literal && node.value === 'this') { + return node.value = name; + } else if (node instanceof Code) { + node.klass = name; + if (node.bound) { + return node.context = name; + } + } + }); + }; + + Class.prototype.addBoundFunctions = function(o) { + var bvar, lhs, _i, _len, _ref2, _results; + if (this.boundFuncs.length) { + _ref2 = this.boundFuncs; + _results = []; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + bvar = _ref2[_i]; + lhs = (new Value(new Literal("this"), [new Access(bvar)])).compile(o); + _results.push(this.ctor.body.unshift(new Literal("" + lhs + " = " + (utility('bind')) + "(" + lhs + ", this)"))); + } + return _results; + } + }; + + Class.prototype.addProperties = function(node, name, o) { + var assign, base, exprs, func, props; + props = node.base.properties.slice(0); + exprs = (function() { + var _results; + _results = []; + while (assign = props.shift()) { + if (assign instanceof Assign) { + base = assign.variable.base; + delete assign.context; + func = assign.value; + if (base.value === 'constructor') { + if (this.ctor) { + throw new Error('cannot define more than one constructor in a class'); + } + if (func.bound) { + throw new Error('cannot define a constructor as a bound function'); + } + if (func instanceof Code) { + assign = this.ctor = func; + } else { + this.externalCtor = o.scope.freeVariable('class'); + assign = new Assign(new Literal(this.externalCtor), func); + } + } else { + if (assign.variable["this"]) { + func["static"] = true; + if (func.bound) { + func.context = name; + } + } else { + assign.variable = new Value(new Literal(name), [new Access(new Literal('prototype')), new Access(base)]); + if (func instanceof Code && func.bound) { + this.boundFuncs.push(base); + func.bound = false; + } + } + } + } + _results.push(assign); + } + return _results; + }).call(this); + return compact(exprs); + }; + + Class.prototype.walkBody = function(name, o) { + var _this = this; + return this.traverseChildren(false, function(child) { + var exps, i, node, _i, _len, _ref2; + if (child instanceof Class) { + return false; + } + if (child instanceof Block) { + _ref2 = exps = child.expressions; + for (i = _i = 0, _len = _ref2.length; _i < _len; i = ++_i) { + node = _ref2[i]; + if (node instanceof Value && node.isObject(true)) { + exps[i] = _this.addProperties(node, name, o); + } + } + return child.expressions = exps = flatten(exps); + } + }); + }; + + Class.prototype.hoistDirectivePrologue = function() { + var expressions, index, node; + index = 0; + expressions = this.body.expressions; + while ((node = expressions[index]) && node instanceof Comment || node instanceof Value && node.isString()) { + ++index; + } + return this.directives = expressions.splice(0, index); + }; + + Class.prototype.ensureConstructor = function(name) { + if (!this.ctor) { + this.ctor = new Code; + if (this.parent) { + this.ctor.body.push(new Literal("" + name + ".__super__.constructor.apply(this, arguments)")); + } + if (this.externalCtor) { + this.ctor.body.push(new Literal("" + this.externalCtor + ".apply(this, arguments)")); + } + this.ctor.body.makeReturn(); + this.body.expressions.unshift(this.ctor); + } + this.ctor.ctor = this.ctor.name = name; + this.ctor.klass = null; + return this.ctor.noReturn = true; + }; + + Class.prototype.compileNode = function(o) { + var call, decl, klass, lname, name, params, _ref2; + decl = this.determineName(); + name = decl || '_Class'; + if (name.reserved) { + name = "_" + name; + } + lname = new Literal(name); + this.hoistDirectivePrologue(); + this.setContext(name); + this.walkBody(name, o); + this.ensureConstructor(name); + this.body.spaced = true; + if (!(this.ctor instanceof Code)) { + this.body.expressions.unshift(this.ctor); + } + this.body.expressions.push(lname); + (_ref2 = this.body.expressions).unshift.apply(_ref2, this.directives); + this.addBoundFunctions(o); + call = Closure.wrap(this.body); + if (this.parent) { + this.superClass = new Literal(o.scope.freeVariable('super', false)); + this.body.expressions.unshift(new Extends(lname, this.superClass)); + call.args.push(this.parent); + params = call.variable.params || call.variable.base.params; + params.push(new Param(this.superClass)); + } + klass = new Parens(call, true); + if (this.variable) { + klass = new Assign(this.variable, klass); + } + return klass.compile(o); + }; + + return Class; + + })(Base); + + exports.Assign = Assign = (function(_super) { + + __extends(Assign, _super); + + function Assign(variable, value, context, options) { + var forbidden, name, _ref2; + this.variable = variable; + this.value = value; + this.context = context; + this.param = options && options.param; + this.subpattern = options && options.subpattern; + forbidden = (_ref2 = (name = this.variable.unwrapAll().value), __indexOf.call(STRICT_PROSCRIBED, _ref2) >= 0); + if (forbidden && this.context !== 'object') { + throw SyntaxError("variable name may not be \"" + name + "\""); + } + } + + Assign.prototype.children = ['variable', 'value']; + + Assign.prototype.isStatement = function(o) { + return (o != null ? o.level : void 0) === LEVEL_TOP && (this.context != null) && __indexOf.call(this.context, "?") >= 0; + }; + + Assign.prototype.assigns = function(name) { + return this[this.context === 'object' ? 'value' : 'variable'].assigns(name); + }; + + Assign.prototype.unfoldSoak = function(o) { + return unfoldSoak(o, this, 'variable'); + }; + + Assign.prototype.compileNode = function(o) { + var isValue, match, name, val, varBase, _ref2, _ref3, _ref4, _ref5; + if (isValue = this.variable instanceof Value) { + if (this.variable.isArray() || this.variable.isObject()) { + return this.compilePatternMatch(o); + } + if (this.variable.isSplice()) { + return this.compileSplice(o); + } + if ((_ref2 = this.context) === '||=' || _ref2 === '&&=' || _ref2 === '?=') { + return this.compileConditional(o); + } + } + name = this.variable.compile(o, LEVEL_LIST); + if (!this.context) { + if (!(varBase = this.variable.unwrapAll()).isAssignable()) { + throw SyntaxError("\"" + (this.variable.compile(o)) + "\" cannot be assigned."); + } + if (!(typeof varBase.hasProperties === "function" ? varBase.hasProperties() : void 0)) { + if (this.param) { + o.scope.add(name, 'var'); + } else { + o.scope.find(name); + } + } + } + if (this.value instanceof Code && (match = METHOD_DEF.exec(name))) { + if (match[1]) { + this.value.klass = match[1]; + } + this.value.name = (_ref3 = (_ref4 = (_ref5 = match[2]) != null ? _ref5 : match[3]) != null ? _ref4 : match[4]) != null ? _ref3 : match[5]; + } + val = this.value.compile(o, LEVEL_LIST); + if (this.context === 'object') { + return "" + name + ": " + val; + } + val = name + (" " + (this.context || '=') + " ") + val; + if (o.level <= LEVEL_LIST) { + return val; + } else { + return "(" + val + ")"; + } + }; + + Assign.prototype.compilePatternMatch = function(o) { + var acc, assigns, code, i, idx, isObject, ivar, name, obj, objects, olen, ref, rest, splat, top, val, value, vvar, _i, _len, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8; + top = o.level === LEVEL_TOP; + value = this.value; + objects = this.variable.base.objects; + if (!(olen = objects.length)) { + code = value.compile(o); + if (o.level >= LEVEL_OP) { + return "(" + code + ")"; + } else { + return code; + } + } + isObject = this.variable.isObject(); + if (top && olen === 1 && !((obj = objects[0]) instanceof Splat)) { + if (obj instanceof Assign) { + _ref2 = obj, (_ref3 = _ref2.variable, idx = _ref3.base), obj = _ref2.value; + } else { + if (obj.base instanceof Parens) { + _ref4 = new Value(obj.unwrapAll()).cacheReference(o), obj = _ref4[0], idx = _ref4[1]; + } else { + idx = isObject ? obj["this"] ? obj.properties[0].name : obj : new Literal(0); + } + } + acc = IDENTIFIER.test(idx.unwrap().value || 0); + value = new Value(value); + value.properties.push(new (acc ? Access : Index)(idx)); + if (_ref5 = obj.unwrap().value, __indexOf.call(RESERVED, _ref5) >= 0) { + throw new SyntaxError("assignment to a reserved word: " + (obj.compile(o)) + " = " + (value.compile(o))); + } + return new Assign(obj, value, null, { + param: this.param + }).compile(o, LEVEL_TOP); + } + vvar = value.compile(o, LEVEL_LIST); + assigns = []; + splat = false; + if (!IDENTIFIER.test(vvar) || this.variable.assigns(vvar)) { + assigns.push("" + (ref = o.scope.freeVariable('ref')) + " = " + vvar); + vvar = ref; + } + for (i = _i = 0, _len = objects.length; _i < _len; i = ++_i) { + obj = objects[i]; + idx = i; + if (isObject) { + if (obj instanceof Assign) { + _ref6 = obj, (_ref7 = _ref6.variable, idx = _ref7.base), obj = _ref6.value; + } else { + if (obj.base instanceof Parens) { + _ref8 = new Value(obj.unwrapAll()).cacheReference(o), obj = _ref8[0], idx = _ref8[1]; + } else { + idx = obj["this"] ? obj.properties[0].name : obj; + } + } + } + if (!splat && obj instanceof Splat) { + name = obj.name.unwrap().value; + obj = obj.unwrap(); + val = "" + olen + " <= " + vvar + ".length ? " + (utility('slice')) + ".call(" + vvar + ", " + i; + if (rest = olen - i - 1) { + ivar = o.scope.freeVariable('i'); + val += ", " + ivar + " = " + vvar + ".length - " + rest + ") : (" + ivar + " = " + i + ", [])"; + } else { + val += ") : []"; + } + val = new Literal(val); + splat = "" + ivar + "++"; + } else { + name = obj.unwrap().value; + if (obj instanceof Splat) { + obj = obj.name.compile(o); + throw new SyntaxError("multiple splats are disallowed in an assignment: " + obj + "..."); + } + if (typeof idx === 'number') { + idx = new Literal(splat || idx); + acc = false; + } else { + acc = isObject && IDENTIFIER.test(idx.unwrap().value || 0); + } + val = new Value(new Literal(vvar), [new (acc ? Access : Index)(idx)]); + } + if ((name != null) && __indexOf.call(RESERVED, name) >= 0) { + throw new SyntaxError("assignment to a reserved word: " + (obj.compile(o)) + " = " + (val.compile(o))); + } + assigns.push(new Assign(obj, val, null, { + param: this.param, + subpattern: true + }).compile(o, LEVEL_LIST)); + } + if (!(top || this.subpattern)) { + assigns.push(vvar); + } + code = assigns.join(', '); + if (o.level < LEVEL_LIST) { + return code; + } else { + return "(" + code + ")"; + } + }; + + Assign.prototype.compileConditional = function(o) { + var left, right, _ref2; + _ref2 = this.variable.cacheReference(o), left = _ref2[0], right = _ref2[1]; + if (!left.properties.length && left.base instanceof Literal && left.base.value !== "this" && !o.scope.check(left.base.value)) { + throw new Error("the variable \"" + left.base.value + "\" can't be assigned with " + this.context + " because it has not been defined."); + } + if (__indexOf.call(this.context, "?") >= 0) { + o.isExistentialEquals = true; + } + return new Op(this.context.slice(0, -1), left, new Assign(right, this.value, '=')).compile(o); + }; + + Assign.prototype.compileSplice = function(o) { + var code, exclusive, from, fromDecl, fromRef, name, to, valDef, valRef, _ref2, _ref3, _ref4; + _ref2 = this.variable.properties.pop().range, from = _ref2.from, to = _ref2.to, exclusive = _ref2.exclusive; + name = this.variable.compile(o); + _ref3 = (from != null ? from.cache(o, LEVEL_OP) : void 0) || ['0', '0'], fromDecl = _ref3[0], fromRef = _ref3[1]; + if (to) { + if ((from != null ? from.isSimpleNumber() : void 0) && to.isSimpleNumber()) { + to = +to.compile(o) - +fromRef; + if (!exclusive) { + to += 1; + } + } else { + to = to.compile(o, LEVEL_ACCESS) + ' - ' + fromRef; + if (!exclusive) { + to += ' + 1'; + } + } + } else { + to = "9e9"; + } + _ref4 = this.value.cache(o, LEVEL_LIST), valDef = _ref4[0], valRef = _ref4[1]; + code = "[].splice.apply(" + name + ", [" + fromDecl + ", " + to + "].concat(" + valDef + ")), " + valRef; + if (o.level > LEVEL_TOP) { + return "(" + code + ")"; + } else { + return code; + } + }; + + return Assign; + + })(Base); + + exports.Code = Code = (function(_super) { + + __extends(Code, _super); + + function Code(params, body, tag) { + this.params = params || []; + this.body = body || new Block; + this.bound = tag === 'boundfunc'; + if (this.bound) { + this.context = '_this'; + } + } + + Code.prototype.children = ['params', 'body']; + + Code.prototype.isStatement = function() { + return !!this.ctor; + }; + + Code.prototype.jumps = NO; + + Code.prototype.compileNode = function(o) { + var code, exprs, i, idt, lit, name, p, param, params, ref, splats, uniqs, val, wasEmpty, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8; + o.scope = new Scope(o.scope, this.body, this); + o.scope.shared = del(o, 'sharedScope'); + o.indent += TAB; + delete o.bare; + delete o.isExistentialEquals; + params = []; + exprs = []; + _ref2 = this.paramNames(); + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + name = _ref2[_i]; + if (!o.scope.check(name)) { + o.scope.parameter(name); + } + } + _ref3 = this.params; + for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) { + param = _ref3[_j]; + if (!param.splat) { + continue; + } + _ref4 = this.params; + for (_k = 0, _len2 = _ref4.length; _k < _len2; _k++) { + p = _ref4[_k].name; + if (p["this"]) { + p = p.properties[0].name; + } + if (p.value) { + o.scope.add(p.value, 'var', true); + } + } + splats = new Assign(new Value(new Arr((function() { + var _l, _len3, _ref5, _results; + _ref5 = this.params; + _results = []; + for (_l = 0, _len3 = _ref5.length; _l < _len3; _l++) { + p = _ref5[_l]; + _results.push(p.asReference(o)); + } + return _results; + }).call(this))), new Value(new Literal('arguments'))); + break; + } + _ref5 = this.params; + for (_l = 0, _len3 = _ref5.length; _l < _len3; _l++) { + param = _ref5[_l]; + if (param.isComplex()) { + val = ref = param.asReference(o); + if (param.value) { + val = new Op('?', ref, param.value); + } + exprs.push(new Assign(new Value(param.name), val, '=', { + param: true + })); + } else { + ref = param; + if (param.value) { + lit = new Literal(ref.name.value + ' == null'); + val = new Assign(new Value(param.name), param.value, '='); + exprs.push(new If(lit, val)); + } + } + if (!splats) { + params.push(ref); + } + } + wasEmpty = this.body.isEmpty(); + if (splats) { + exprs.unshift(splats); + } + if (exprs.length) { + (_ref6 = this.body.expressions).unshift.apply(_ref6, exprs); + } + for (i = _m = 0, _len4 = params.length; _m < _len4; i = ++_m) { + p = params[i]; + o.scope.parameter(params[i] = p.compile(o)); + } + uniqs = []; + _ref7 = this.paramNames(); + for (_n = 0, _len5 = _ref7.length; _n < _len5; _n++) { + name = _ref7[_n]; + if (__indexOf.call(uniqs, name) >= 0) { + throw SyntaxError("multiple parameters named '" + name + "'"); + } + uniqs.push(name); + } + if (!(wasEmpty || this.noReturn)) { + this.body.makeReturn(); + } + if (this.bound) { + if ((_ref8 = o.scope.parent.method) != null ? _ref8.bound : void 0) { + this.bound = this.context = o.scope.parent.method.context; + } else if (!this["static"]) { + o.scope.parent.assign('_this', 'this'); + } + } + idt = o.indent; + code = 'function'; + if (this.ctor) { + code += ' ' + this.name; + } + code += '(' + params.join(', ') + ') {'; + if (!this.body.isEmpty()) { + code += "\n" + (this.body.compileWithDeclarations(o)) + "\n" + this.tab; + } + code += '}'; + if (this.ctor) { + return this.tab + code; + } + if (this.front || (o.level >= LEVEL_ACCESS)) { + return "(" + code + ")"; + } else { + return code; + } + }; + + Code.prototype.paramNames = function() { + var names, param, _i, _len, _ref2; + names = []; + _ref2 = this.params; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + param = _ref2[_i]; + names.push.apply(names, param.names()); + } + return names; + }; + + Code.prototype.traverseChildren = function(crossScope, func) { + if (crossScope) { + return Code.__super__.traverseChildren.call(this, crossScope, func); + } + }; + + return Code; + + })(Base); + + exports.Param = Param = (function(_super) { + + __extends(Param, _super); + + function Param(name, value, splat) { + var _ref2; + this.name = name; + this.value = value; + this.splat = splat; + if (_ref2 = (name = this.name.unwrapAll().value), __indexOf.call(STRICT_PROSCRIBED, _ref2) >= 0) { + throw SyntaxError("parameter name \"" + name + "\" is not allowed"); + } + } + + Param.prototype.children = ['name', 'value']; + + Param.prototype.compile = function(o) { + return this.name.compile(o, LEVEL_LIST); + }; + + Param.prototype.asReference = function(o) { + var node; + if (this.reference) { + return this.reference; + } + node = this.name; + if (node["this"]) { + node = node.properties[0].name; + if (node.value.reserved) { + node = new Literal(o.scope.freeVariable(node.value)); + } + } else if (node.isComplex()) { + node = new Literal(o.scope.freeVariable('arg')); + } + node = new Value(node); + if (this.splat) { + node = new Splat(node); + } + return this.reference = node; + }; + + Param.prototype.isComplex = function() { + return this.name.isComplex(); + }; + + Param.prototype.names = function(name) { + var atParam, names, obj, _i, _len, _ref2; + if (name == null) { + name = this.name; + } + atParam = function(obj) { + var value; + value = obj.properties[0].name.value; + if (value.reserved) { + return []; + } else { + return [value]; + } + }; + if (name instanceof Literal) { + return [name.value]; + } + if (name instanceof Value) { + return atParam(name); + } + names = []; + _ref2 = name.objects; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + obj = _ref2[_i]; + if (obj instanceof Assign) { + names.push(obj.value.unwrap().value); + } else if (obj instanceof Splat) { + names.push(obj.name.unwrap().value); + } else if (obj instanceof Value) { + if (obj.isArray() || obj.isObject()) { + names.push.apply(names, this.names(obj.base)); + } else if (obj["this"]) { + names.push.apply(names, atParam(obj)); + } else { + names.push(obj.base.value); + } + } else { + throw SyntaxError("illegal parameter " + (obj.compile())); + } + } + return names; + }; + + return Param; + + })(Base); + + exports.Splat = Splat = (function(_super) { + + __extends(Splat, _super); + + Splat.prototype.children = ['name']; + + Splat.prototype.isAssignable = YES; + + function Splat(name) { + this.name = name.compile ? name : new Literal(name); + } + + Splat.prototype.assigns = function(name) { + return this.name.assigns(name); + }; + + Splat.prototype.compile = function(o) { + if (this.index != null) { + return this.compileParam(o); + } else { + return this.name.compile(o); + } + }; + + Splat.prototype.unwrap = function() { + return this.name; + }; + + Splat.compileSplattedArray = function(o, list, apply) { + var args, base, code, i, index, node, _i, _len; + index = -1; + while ((node = list[++index]) && !(node instanceof Splat)) { + continue; + } + if (index >= list.length) { + return ''; + } + if (list.length === 1) { + code = list[0].compile(o, LEVEL_LIST); + if (apply) { + return code; + } + return "" + (utility('slice')) + ".call(" + code + ")"; + } + args = list.slice(index); + for (i = _i = 0, _len = args.length; _i < _len; i = ++_i) { + node = args[i]; + code = node.compile(o, LEVEL_LIST); + args[i] = node instanceof Splat ? "" + (utility('slice')) + ".call(" + code + ")" : "[" + code + "]"; + } + if (index === 0) { + return args[0] + (".concat(" + (args.slice(1).join(', ')) + ")"); + } + base = (function() { + var _j, _len1, _ref2, _results; + _ref2 = list.slice(0, index); + _results = []; + for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) { + node = _ref2[_j]; + _results.push(node.compile(o, LEVEL_LIST)); + } + return _results; + })(); + return "[" + (base.join(', ')) + "].concat(" + (args.join(', ')) + ")"; + }; + + return Splat; + + })(Base); + + exports.While = While = (function(_super) { + + __extends(While, _super); + + function While(condition, options) { + this.condition = (options != null ? options.invert : void 0) ? condition.invert() : condition; + this.guard = options != null ? options.guard : void 0; + } + + While.prototype.children = ['condition', 'guard', 'body']; + + While.prototype.isStatement = YES; + + While.prototype.makeReturn = function(res) { + if (res) { + return While.__super__.makeReturn.apply(this, arguments); + } else { + this.returns = !this.jumps({ + loop: true + }); + return this; + } + }; + + While.prototype.addBody = function(body) { + this.body = body; + return this; + }; + + While.prototype.jumps = function() { + var expressions, node, _i, _len; + expressions = this.body.expressions; + if (!expressions.length) { + return false; + } + for (_i = 0, _len = expressions.length; _i < _len; _i++) { + node = expressions[_i]; + if (node.jumps({ + loop: true + })) { + return node; + } + } + return false; + }; + + While.prototype.compileNode = function(o) { + var body, code, rvar, set; + o.indent += TAB; + set = ''; + body = this.body; + if (body.isEmpty()) { + body = ''; + } else { + if (this.returns) { + body.makeReturn(rvar = o.scope.freeVariable('results')); + set = "" + this.tab + rvar + " = [];\n"; + } + if (this.guard) { + if (body.expressions.length > 1) { + body.expressions.unshift(new If((new Parens(this.guard)).invert(), new Literal("continue"))); + } else { + if (this.guard) { + body = Block.wrap([new If(this.guard, body)]); + } + } + } + body = "\n" + (body.compile(o, LEVEL_TOP)) + "\n" + this.tab; + } + code = set + this.tab + ("while (" + (this.condition.compile(o, LEVEL_PAREN)) + ") {" + body + "}"); + if (this.returns) { + code += "\n" + this.tab + "return " + rvar + ";"; + } + return code; + }; + + return While; + + })(Base); + + exports.Op = Op = (function(_super) { + var CONVERSIONS, INVERSIONS; + + __extends(Op, _super); + + function Op(op, first, second, flip) { + if (op === 'in') { + return new In(first, second); + } + if (op === 'do') { + return this.generateDo(first); + } + if (op === 'new') { + if (first instanceof Call && !first["do"] && !first.isNew) { + return first.newInstance(); + } + if (first instanceof Code && first.bound || first["do"]) { + first = new Parens(first); + } + } + this.operator = CONVERSIONS[op] || op; + this.first = first; + this.second = second; + this.flip = !!flip; + return this; + } + + CONVERSIONS = { + '==': '===', + '!=': '!==', + 'of': 'in' + }; + + INVERSIONS = { + '!==': '===', + '===': '!==' + }; + + Op.prototype.children = ['first', 'second']; + + Op.prototype.isSimpleNumber = NO; + + Op.prototype.isUnary = function() { + return !this.second; + }; + + Op.prototype.isComplex = function() { + var _ref2; + return !(this.isUnary() && ((_ref2 = this.operator) === '+' || _ref2 === '-')) || this.first.isComplex(); + }; + + Op.prototype.isChainable = function() { + var _ref2; + return (_ref2 = this.operator) === '<' || _ref2 === '>' || _ref2 === '>=' || _ref2 === '<=' || _ref2 === '===' || _ref2 === '!=='; + }; + + Op.prototype.invert = function() { + var allInvertable, curr, fst, op, _ref2; + if (this.isChainable() && this.first.isChainable()) { + allInvertable = true; + curr = this; + while (curr && curr.operator) { + allInvertable && (allInvertable = curr.operator in INVERSIONS); + curr = curr.first; + } + if (!allInvertable) { + return new Parens(this).invert(); + } + curr = this; + while (curr && curr.operator) { + curr.invert = !curr.invert; + curr.operator = INVERSIONS[curr.operator]; + curr = curr.first; + } + return this; + } else if (op = INVERSIONS[this.operator]) { + this.operator = op; + if (this.first.unwrap() instanceof Op) { + this.first.invert(); + } + return this; + } else if (this.second) { + return new Parens(this).invert(); + } else if (this.operator === '!' && (fst = this.first.unwrap()) instanceof Op && ((_ref2 = fst.operator) === '!' || _ref2 === 'in' || _ref2 === 'instanceof')) { + return fst; + } else { + return new Op('!', this); + } + }; + + Op.prototype.unfoldSoak = function(o) { + var _ref2; + return ((_ref2 = this.operator) === '++' || _ref2 === '--' || _ref2 === 'delete') && unfoldSoak(o, this, 'first'); + }; + + Op.prototype.generateDo = function(exp) { + var call, func, param, passedParams, ref, _i, _len, _ref2; + passedParams = []; + func = exp instanceof Assign && (ref = exp.value.unwrap()) instanceof Code ? ref : exp; + _ref2 = func.params || []; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + param = _ref2[_i]; + if (param.value) { + passedParams.push(param.value); + delete param.value; + } else { + passedParams.push(param); + } + } + call = new Call(exp, passedParams); + call["do"] = true; + return call; + }; + + Op.prototype.compileNode = function(o) { + var code, isChain, _ref2, _ref3; + isChain = this.isChainable() && this.first.isChainable(); + if (!isChain) { + this.first.front = this.front; + } + if (this.operator === 'delete' && o.scope.check(this.first.unwrapAll().value)) { + throw SyntaxError('delete operand may not be argument or var'); + } + if (((_ref2 = this.operator) === '--' || _ref2 === '++') && (_ref3 = this.first.unwrapAll().value, __indexOf.call(STRICT_PROSCRIBED, _ref3) >= 0)) { + throw SyntaxError('prefix increment/decrement may not have eval or arguments operand'); + } + if (this.isUnary()) { + return this.compileUnary(o); + } + if (isChain) { + return this.compileChain(o); + } + if (this.operator === '?') { + return this.compileExistence(o); + } + code = this.first.compile(o, LEVEL_OP) + ' ' + this.operator + ' ' + this.second.compile(o, LEVEL_OP); + if (o.level <= LEVEL_OP) { + return code; + } else { + return "(" + code + ")"; + } + }; + + Op.prototype.compileChain = function(o) { + var code, fst, shared, _ref2; + _ref2 = this.first.second.cache(o), this.first.second = _ref2[0], shared = _ref2[1]; + fst = this.first.compile(o, LEVEL_OP); + code = "" + fst + " " + (this.invert ? '&&' : '||') + " " + (shared.compile(o)) + " " + this.operator + " " + (this.second.compile(o, LEVEL_OP)); + return "(" + code + ")"; + }; + + Op.prototype.compileExistence = function(o) { + var fst, ref; + if (this.first.isComplex()) { + ref = new Literal(o.scope.freeVariable('ref')); + fst = new Parens(new Assign(ref, this.first)); + } else { + fst = this.first; + ref = fst; + } + return new If(new Existence(fst), ref, { + type: 'if' + }).addElse(this.second).compile(o); + }; + + Op.prototype.compileUnary = function(o) { + var op, parts, plusMinus; + if (o.level >= LEVEL_ACCESS) { + return (new Parens(this)).compile(o); + } + parts = [op = this.operator]; + plusMinus = op === '+' || op === '-'; + if ((op === 'new' || op === 'typeof' || op === 'delete') || plusMinus && this.first instanceof Op && this.first.operator === op) { + parts.push(' '); + } + if ((plusMinus && this.first instanceof Op) || (op === 'new' && this.first.isStatement(o))) { + this.first = new Parens(this.first); + } + parts.push(this.first.compile(o, LEVEL_OP)); + if (this.flip) { + parts.reverse(); + } + return parts.join(''); + }; + + Op.prototype.toString = function(idt) { + return Op.__super__.toString.call(this, idt, this.constructor.name + ' ' + this.operator); + }; + + return Op; + + })(Base); + + exports.In = In = (function(_super) { + + __extends(In, _super); + + function In(object, array) { + this.object = object; + this.array = array; + } + + In.prototype.children = ['object', 'array']; + + In.prototype.invert = NEGATE; + + In.prototype.compileNode = function(o) { + var hasSplat, obj, _i, _len, _ref2; + if (this.array instanceof Value && this.array.isArray()) { + _ref2 = this.array.base.objects; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + obj = _ref2[_i]; + if (!(obj instanceof Splat)) { + continue; + } + hasSplat = true; + break; + } + if (!hasSplat) { + return this.compileOrTest(o); + } + } + return this.compileLoopTest(o); + }; + + In.prototype.compileOrTest = function(o) { + var cmp, cnj, i, item, ref, sub, tests, _ref2, _ref3; + if (this.array.base.objects.length === 0) { + return "" + (!!this.negated); + } + _ref2 = this.object.cache(o, LEVEL_OP), sub = _ref2[0], ref = _ref2[1]; + _ref3 = this.negated ? [' !== ', ' && '] : [' === ', ' || '], cmp = _ref3[0], cnj = _ref3[1]; + tests = (function() { + var _i, _len, _ref4, _results; + _ref4 = this.array.base.objects; + _results = []; + for (i = _i = 0, _len = _ref4.length; _i < _len; i = ++_i) { + item = _ref4[i]; + _results.push((i ? ref : sub) + cmp + item.compile(o, LEVEL_ACCESS)); + } + return _results; + }).call(this); + tests = tests.join(cnj); + if (o.level < LEVEL_OP) { + return tests; + } else { + return "(" + tests + ")"; + } + }; + + In.prototype.compileLoopTest = function(o) { + var code, ref, sub, _ref2; + _ref2 = this.object.cache(o, LEVEL_LIST), sub = _ref2[0], ref = _ref2[1]; + code = utility('indexOf') + (".call(" + (this.array.compile(o, LEVEL_LIST)) + ", " + ref + ") ") + (this.negated ? '< 0' : '>= 0'); + if (sub === ref) { + return code; + } + code = sub + ', ' + code; + if (o.level < LEVEL_LIST) { + return code; + } else { + return "(" + code + ")"; + } + }; + + In.prototype.toString = function(idt) { + return In.__super__.toString.call(this, idt, this.constructor.name + (this.negated ? '!' : '')); + }; + + return In; + + })(Base); + + exports.Try = Try = (function(_super) { + + __extends(Try, _super); + + function Try(attempt, error, recovery, ensure) { + this.attempt = attempt; + this.error = error; + this.recovery = recovery; + this.ensure = ensure; + } + + Try.prototype.children = ['attempt', 'recovery', 'ensure']; + + Try.prototype.isStatement = YES; + + Try.prototype.jumps = function(o) { + var _ref2; + return this.attempt.jumps(o) || ((_ref2 = this.recovery) != null ? _ref2.jumps(o) : void 0); + }; + + Try.prototype.makeReturn = function(res) { + if (this.attempt) { + this.attempt = this.attempt.makeReturn(res); + } + if (this.recovery) { + this.recovery = this.recovery.makeReturn(res); + } + return this; + }; + + Try.prototype.compileNode = function(o) { + var catchPart, ensurePart, errorPart, tryPart; + o.indent += TAB; + errorPart = this.error ? " (" + (this.error.compile(o)) + ") " : ' '; + tryPart = this.attempt.compile(o, LEVEL_TOP); + catchPart = (function() { + var _ref2; + if (this.recovery) { + if (_ref2 = this.error.value, __indexOf.call(STRICT_PROSCRIBED, _ref2) >= 0) { + throw SyntaxError("catch variable may not be \"" + this.error.value + "\""); + } + if (!o.scope.check(this.error.value)) { + o.scope.add(this.error.value, 'param'); + } + return " catch" + errorPart + "{\n" + (this.recovery.compile(o, LEVEL_TOP)) + "\n" + this.tab + "}"; + } else if (!(this.ensure || this.recovery)) { + return ' catch (_error) {}'; + } + }).call(this); + ensurePart = this.ensure ? " finally {\n" + (this.ensure.compile(o, LEVEL_TOP)) + "\n" + this.tab + "}" : ''; + return "" + this.tab + "try {\n" + tryPart + "\n" + this.tab + "}" + (catchPart || '') + ensurePart; + }; + + return Try; + + })(Base); + + exports.Throw = Throw = (function(_super) { + + __extends(Throw, _super); + + function Throw(expression) { + this.expression = expression; + } + + Throw.prototype.children = ['expression']; + + Throw.prototype.isStatement = YES; + + Throw.prototype.jumps = NO; + + Throw.prototype.makeReturn = THIS; + + Throw.prototype.compileNode = function(o) { + return this.tab + ("throw " + (this.expression.compile(o)) + ";"); + }; + + return Throw; + + })(Base); + + exports.Existence = Existence = (function(_super) { + + __extends(Existence, _super); + + function Existence(expression) { + this.expression = expression; + } + + Existence.prototype.children = ['expression']; + + Existence.prototype.invert = NEGATE; + + Existence.prototype.compileNode = function(o) { + var cmp, cnj, code, _ref2; + this.expression.front = this.front; + code = this.expression.compile(o, LEVEL_OP); + if (IDENTIFIER.test(code) && !o.scope.check(code)) { + _ref2 = this.negated ? ['===', '||'] : ['!==', '&&'], cmp = _ref2[0], cnj = _ref2[1]; + code = "typeof " + code + " " + cmp + " \"undefined\" " + cnj + " " + code + " " + cmp + " null"; + } else { + code = "" + code + " " + (this.negated ? '==' : '!=') + " null"; + } + if (o.level <= LEVEL_COND) { + return code; + } else { + return "(" + code + ")"; + } + }; + + return Existence; + + })(Base); + + exports.Parens = Parens = (function(_super) { + + __extends(Parens, _super); + + function Parens(body) { + this.body = body; + } + + Parens.prototype.children = ['body']; + + Parens.prototype.unwrap = function() { + return this.body; + }; + + Parens.prototype.isComplex = function() { + return this.body.isComplex(); + }; + + Parens.prototype.compileNode = function(o) { + var bare, code, expr; + expr = this.body.unwrap(); + if (expr instanceof Value && expr.isAtomic()) { + expr.front = this.front; + return expr.compile(o); + } + code = expr.compile(o, LEVEL_PAREN); + bare = o.level < LEVEL_OP && (expr instanceof Op || expr instanceof Call || (expr instanceof For && expr.returns)); + if (bare) { + return code; + } else { + return "(" + code + ")"; + } + }; + + return Parens; + + })(Base); + + exports.For = For = (function(_super) { + + __extends(For, _super); + + function For(body, source) { + var _ref2; + this.source = source.source, this.guard = source.guard, this.step = source.step, this.name = source.name, this.index = source.index; + this.body = Block.wrap([body]); + this.own = !!source.own; + this.object = !!source.object; + if (this.object) { + _ref2 = [this.index, this.name], this.name = _ref2[0], this.index = _ref2[1]; + } + if (this.index instanceof Value) { + throw SyntaxError('index cannot be a pattern matching expression'); + } + this.range = this.source instanceof Value && this.source.base instanceof Range && !this.source.properties.length; + this.pattern = this.name instanceof Value; + if (this.range && this.index) { + throw SyntaxError('indexes do not apply to range loops'); + } + if (this.range && this.pattern) { + throw SyntaxError('cannot pattern match over range loops'); + } + this.returns = false; + } + + For.prototype.children = ['body', 'source', 'guard', 'step']; + + For.prototype.compileNode = function(o) { + var body, defPart, forPart, forVarPart, guardPart, idt1, index, ivar, kvar, kvarAssign, lastJumps, lvar, name, namePart, ref, resultPart, returnResult, rvar, scope, source, stepPart, stepvar, svar, varPart, _ref2; + body = Block.wrap([this.body]); + lastJumps = (_ref2 = last(body.expressions)) != null ? _ref2.jumps() : void 0; + if (lastJumps && lastJumps instanceof Return) { + this.returns = false; + } + source = this.range ? this.source.base : this.source; + scope = o.scope; + name = this.name && this.name.compile(o, LEVEL_LIST); + index = this.index && this.index.compile(o, LEVEL_LIST); + if (name && !this.pattern) { + scope.find(name); + } + if (index) { + scope.find(index); + } + if (this.returns) { + rvar = scope.freeVariable('results'); + } + ivar = (this.object && index) || scope.freeVariable('i'); + kvar = (this.range && name) || index || ivar; + kvarAssign = kvar !== ivar ? "" + kvar + " = " : ""; + if (this.step && !this.range) { + stepvar = scope.freeVariable("step"); + } + if (this.pattern) { + name = ivar; + } + varPart = ''; + guardPart = ''; + defPart = ''; + idt1 = this.tab + TAB; + if (this.range) { + forPart = source.compile(merge(o, { + index: ivar, + name: name, + step: this.step + })); + } else { + svar = this.source.compile(o, LEVEL_LIST); + if ((name || this.own) && !IDENTIFIER.test(svar)) { + defPart = "" + this.tab + (ref = scope.freeVariable('ref')) + " = " + svar + ";\n"; + svar = ref; + } + if (name && !this.pattern) { + namePart = "" + name + " = " + svar + "[" + kvar + "]"; + } + if (!this.object) { + lvar = scope.freeVariable('len'); + forVarPart = "" + kvarAssign + ivar + " = 0, " + lvar + " = " + svar + ".length"; + if (this.step) { + forVarPart += ", " + stepvar + " = " + (this.step.compile(o, LEVEL_OP)); + } + stepPart = "" + kvarAssign + (this.step ? "" + ivar + " += " + stepvar : (kvar !== ivar ? "++" + ivar : "" + ivar + "++")); + forPart = "" + forVarPart + "; " + ivar + " < " + lvar + "; " + stepPart; + } + } + if (this.returns) { + resultPart = "" + this.tab + rvar + " = [];\n"; + returnResult = "\n" + this.tab + "return " + rvar + ";"; + body.makeReturn(rvar); + } + if (this.guard) { + if (body.expressions.length > 1) { + body.expressions.unshift(new If((new Parens(this.guard)).invert(), new Literal("continue"))); + } else { + if (this.guard) { + body = Block.wrap([new If(this.guard, body)]); + } + } + } + if (this.pattern) { + body.expressions.unshift(new Assign(this.name, new Literal("" + svar + "[" + kvar + "]"))); + } + defPart += this.pluckDirectCall(o, body); + if (namePart) { + varPart = "\n" + idt1 + namePart + ";"; + } + if (this.object) { + forPart = "" + kvar + " in " + svar; + if (this.own) { + guardPart = "\n" + idt1 + "if (!" + (utility('hasProp')) + ".call(" + svar + ", " + kvar + ")) continue;"; + } + } + body = body.compile(merge(o, { + indent: idt1 + }), LEVEL_TOP); + if (body) { + body = '\n' + body + '\n'; + } + return "" + defPart + (resultPart || '') + this.tab + "for (" + forPart + ") {" + guardPart + varPart + body + this.tab + "}" + (returnResult || ''); + }; + + For.prototype.pluckDirectCall = function(o, body) { + var base, defs, expr, fn, idx, ref, val, _i, _len, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7; + defs = ''; + _ref2 = body.expressions; + for (idx = _i = 0, _len = _ref2.length; _i < _len; idx = ++_i) { + expr = _ref2[idx]; + expr = expr.unwrapAll(); + if (!(expr instanceof Call)) { + continue; + } + val = expr.variable.unwrapAll(); + if (!((val instanceof Code) || (val instanceof Value && ((_ref3 = val.base) != null ? _ref3.unwrapAll() : void 0) instanceof Code && val.properties.length === 1 && ((_ref4 = (_ref5 = val.properties[0].name) != null ? _ref5.value : void 0) === 'call' || _ref4 === 'apply')))) { + continue; + } + fn = ((_ref6 = val.base) != null ? _ref6.unwrapAll() : void 0) || val; + ref = new Literal(o.scope.freeVariable('fn')); + base = new Value(ref); + if (val.base) { + _ref7 = [base, val], val.base = _ref7[0], base = _ref7[1]; + } + body.expressions[idx] = new Call(base, expr.args); + defs += this.tab + new Assign(ref, fn).compile(o, LEVEL_TOP) + ';\n'; + } + return defs; + }; + + return For; + + })(While); + + exports.Switch = Switch = (function(_super) { + + __extends(Switch, _super); + + function Switch(subject, cases, otherwise) { + this.subject = subject; + this.cases = cases; + this.otherwise = otherwise; + } + + Switch.prototype.children = ['subject', 'cases', 'otherwise']; + + Switch.prototype.isStatement = YES; + + Switch.prototype.jumps = function(o) { + var block, conds, _i, _len, _ref2, _ref3, _ref4; + if (o == null) { + o = { + block: true + }; + } + _ref2 = this.cases; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + _ref3 = _ref2[_i], conds = _ref3[0], block = _ref3[1]; + if (block.jumps(o)) { + return block; + } + } + return (_ref4 = this.otherwise) != null ? _ref4.jumps(o) : void 0; + }; + + Switch.prototype.makeReturn = function(res) { + var pair, _i, _len, _ref2, _ref3; + _ref2 = this.cases; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + pair = _ref2[_i]; + pair[1].makeReturn(res); + } + if (res) { + this.otherwise || (this.otherwise = new Block([new Literal('void 0')])); + } + if ((_ref3 = this.otherwise) != null) { + _ref3.makeReturn(res); + } + return this; + }; + + Switch.prototype.compileNode = function(o) { + var block, body, code, cond, conditions, expr, i, idt1, idt2, _i, _j, _len, _len1, _ref2, _ref3, _ref4, _ref5; + idt1 = o.indent + TAB; + idt2 = o.indent = idt1 + TAB; + code = this.tab + ("switch (" + (((_ref2 = this.subject) != null ? _ref2.compile(o, LEVEL_PAREN) : void 0) || false) + ") {\n"); + _ref3 = this.cases; + for (i = _i = 0, _len = _ref3.length; _i < _len; i = ++_i) { + _ref4 = _ref3[i], conditions = _ref4[0], block = _ref4[1]; + _ref5 = flatten([conditions]); + for (_j = 0, _len1 = _ref5.length; _j < _len1; _j++) { + cond = _ref5[_j]; + if (!this.subject) { + cond = cond.invert(); + } + code += idt1 + ("case " + (cond.compile(o, LEVEL_PAREN)) + ":\n"); + } + if (body = block.compile(o, LEVEL_TOP)) { + code += body + '\n'; + } + if (i === this.cases.length - 1 && !this.otherwise) { + break; + } + expr = this.lastNonComment(block.expressions); + if (expr instanceof Return || (expr instanceof Literal && expr.jumps() && expr.value !== 'debugger')) { + continue; + } + code += idt2 + 'break;\n'; + } + if (this.otherwise && this.otherwise.expressions.length) { + code += idt1 + ("default:\n" + (this.otherwise.compile(o, LEVEL_TOP)) + "\n"); + } + return code + this.tab + '}'; + }; + + return Switch; + + })(Base); + + exports.If = If = (function(_super) { + + __extends(If, _super); + + function If(condition, body, options) { + this.body = body; + if (options == null) { + options = {}; + } + this.condition = options.type === 'unless' ? condition.invert() : condition; + this.elseBody = null; + this.isChain = false; + this.soak = options.soak; + } + + If.prototype.children = ['condition', 'body', 'elseBody']; + + If.prototype.bodyNode = function() { + var _ref2; + return (_ref2 = this.body) != null ? _ref2.unwrap() : void 0; + }; + + If.prototype.elseBodyNode = function() { + var _ref2; + return (_ref2 = this.elseBody) != null ? _ref2.unwrap() : void 0; + }; + + If.prototype.addElse = function(elseBody) { + if (this.isChain) { + this.elseBodyNode().addElse(elseBody); + } else { + this.isChain = elseBody instanceof If; + this.elseBody = this.ensureBlock(elseBody); + } + return this; + }; + + If.prototype.isStatement = function(o) { + var _ref2; + return (o != null ? o.level : void 0) === LEVEL_TOP || this.bodyNode().isStatement(o) || ((_ref2 = this.elseBodyNode()) != null ? _ref2.isStatement(o) : void 0); + }; + + If.prototype.jumps = function(o) { + var _ref2; + return this.body.jumps(o) || ((_ref2 = this.elseBody) != null ? _ref2.jumps(o) : void 0); + }; + + If.prototype.compileNode = function(o) { + if (this.isStatement(o)) { + return this.compileStatement(o); + } else { + return this.compileExpression(o); + } + }; + + If.prototype.makeReturn = function(res) { + if (res) { + this.elseBody || (this.elseBody = new Block([new Literal('void 0')])); + } + this.body && (this.body = new Block([this.body.makeReturn(res)])); + this.elseBody && (this.elseBody = new Block([this.elseBody.makeReturn(res)])); + return this; + }; + + If.prototype.ensureBlock = function(node) { + if (node instanceof Block) { + return node; + } else { + return new Block([node]); + } + }; + + If.prototype.compileStatement = function(o) { + var body, child, cond, exeq, ifPart; + child = del(o, 'chainChild'); + exeq = del(o, 'isExistentialEquals'); + if (exeq) { + return new If(this.condition.invert(), this.elseBodyNode(), { + type: 'if' + }).compile(o); + } + cond = this.condition.compile(o, LEVEL_PAREN); + o.indent += TAB; + body = this.ensureBlock(this.body); + ifPart = "if (" + cond + ") {\n" + (body.compile(o)) + "\n" + this.tab + "}"; + if (!child) { + ifPart = this.tab + ifPart; + } + if (!this.elseBody) { + return ifPart; + } + return ifPart + ' else ' + (this.isChain ? (o.indent = this.tab, o.chainChild = true, this.elseBody.unwrap().compile(o, LEVEL_TOP)) : "{\n" + (this.elseBody.compile(o, LEVEL_TOP)) + "\n" + this.tab + "}"); + }; + + If.prototype.compileExpression = function(o) { + var alt, body, code, cond; + cond = this.condition.compile(o, LEVEL_COND); + body = this.bodyNode().compile(o, LEVEL_LIST); + alt = this.elseBodyNode() ? this.elseBodyNode().compile(o, LEVEL_LIST) : 'void 0'; + code = "" + cond + " ? " + body + " : " + alt; + if (o.level >= LEVEL_COND) { + return "(" + code + ")"; + } else { + return code; + } + }; + + If.prototype.unfoldSoak = function() { + return this.soak && this; + }; + + return If; + + })(Base); + + Closure = { + wrap: function(expressions, statement, noReturn) { + var args, call, func, mentionsArgs, meth; + if (expressions.jumps()) { + return expressions; + } + func = new Code([], Block.wrap([expressions])); + args = []; + if ((mentionsArgs = expressions.contains(this.literalArgs)) || expressions.contains(this.literalThis)) { + meth = new Literal(mentionsArgs ? 'apply' : 'call'); + args = [new Literal('this')]; + if (mentionsArgs) { + args.push(new Literal('arguments')); + } + func = new Value(func, [new Access(meth)]); + } + func.noReturn = noReturn; + call = new Call(func, args); + if (statement) { + return Block.wrap([call]); + } else { + return call; + } + }, + literalArgs: function(node) { + return node instanceof Literal && node.value === 'arguments' && !node.asKey; + }, + literalThis: function(node) { + return (node instanceof Literal && node.value === 'this' && !node.asKey) || (node instanceof Code && node.bound) || (node instanceof Call && node.isSuper); + } + }; + + unfoldSoak = function(o, parent, name) { + var ifn; + if (!(ifn = parent[name].unfoldSoak(o))) { + return; + } + parent[name] = ifn.body; + ifn.body = new Value(parent); + return ifn; + }; + + UTILITIES = { + "extends": function() { + return "function(child, parent) { for (var key in parent) { if (" + (utility('hasProp')) + ".call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }"; + }, + bind: function() { + return 'function(fn, me){ return function(){ return fn.apply(me, arguments); }; }'; + }, + indexOf: function() { + return "[].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }"; + }, + hasProp: function() { + return '{}.hasOwnProperty'; + }, + slice: function() { + return '[].slice'; + } + }; + + LEVEL_TOP = 1; + + LEVEL_PAREN = 2; + + LEVEL_LIST = 3; + + LEVEL_COND = 4; + + LEVEL_OP = 5; + + LEVEL_ACCESS = 6; + + TAB = ' '; + + IDENTIFIER_STR = "[$A-Za-z_\\x7f-\\uffff][$\\w\\x7f-\\uffff]*"; + + IDENTIFIER = RegExp("^" + IDENTIFIER_STR + "$"); + + SIMPLENUM = /^[+-]?\d+$/; + + METHOD_DEF = RegExp("^(?:(" + IDENTIFIER_STR + ")\\.prototype(?:\\.(" + IDENTIFIER_STR + ")|\\[(\"(?:[^\\\\\"\\r\\n]|\\\\.)*\"|'(?:[^\\\\'\\r\\n]|\\\\.)*')\\]|\\[(0x[\\da-fA-F]+|\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\]))|(" + IDENTIFIER_STR + ")$"); + + IS_STRING = /^['"]/; + + utility = function(name) { + var ref; + ref = "__" + name; + Scope.root.assign(ref, UTILITIES[name]()); + return ref; + }; + + multident = function(code, tab) { + code = code.replace(/\n/g, '$&' + tab); + return code.replace(/\s+$/, ''); + }; + + +}); \ No newline at end of file diff --git a/lib/ace/mode/coffee/parser.js b/lib/ace/mode/coffee/parser.js new file mode 100644 index 0000000000..3fb271e697 --- /dev/null +++ b/lib/ace/mode/coffee/parser.js @@ -0,0 +1,694 @@ +/** + * Copyright (c) 2009-2012 Jeremy Ashkenas + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +define(function(require, exports, module) { +/* Jison generated parser */ + +var parser = {trace: function trace() { }, +yy: {}, +symbols_: {"error":2,"Root":3,"Body":4,"Block":5,"TERMINATOR":6,"Line":7,"Expression":8,"Statement":9,"Return":10,"Comment":11,"STATEMENT":12,"Value":13,"Invocation":14,"Code":15,"Operation":16,"Assign":17,"If":18,"Try":19,"While":20,"For":21,"Switch":22,"Class":23,"Throw":24,"INDENT":25,"OUTDENT":26,"Identifier":27,"IDENTIFIER":28,"AlphaNumeric":29,"NUMBER":30,"STRING":31,"Literal":32,"JS":33,"REGEX":34,"DEBUGGER":35,"UNDEFINED":36,"NULL":37,"BOOL":38,"Assignable":39,"=":40,"AssignObj":41,"ObjAssignable":42,":":43,"ThisProperty":44,"RETURN":45,"HERECOMMENT":46,"PARAM_START":47,"ParamList":48,"PARAM_END":49,"FuncGlyph":50,"->":51,"=>":52,"OptComma":53,",":54,"Param":55,"ParamVar":56,"...":57,"Array":58,"Object":59,"Splat":60,"SimpleAssignable":61,"Accessor":62,"Parenthetical":63,"Range":64,"This":65,".":66,"?.":67,"::":68,"Index":69,"INDEX_START":70,"IndexValue":71,"INDEX_END":72,"INDEX_SOAK":73,"Slice":74,"{":75,"AssignList":76,"}":77,"CLASS":78,"EXTENDS":79,"OptFuncExist":80,"Arguments":81,"SUPER":82,"FUNC_EXIST":83,"CALL_START":84,"CALL_END":85,"ArgList":86,"THIS":87,"@":88,"[":89,"]":90,"RangeDots":91,"..":92,"Arg":93,"SimpleArgs":94,"TRY":95,"Catch":96,"FINALLY":97,"CATCH":98,"THROW":99,"(":100,")":101,"WhileSource":102,"WHILE":103,"WHEN":104,"UNTIL":105,"Loop":106,"LOOP":107,"ForBody":108,"FOR":109,"ForStart":110,"ForSource":111,"ForVariables":112,"OWN":113,"ForValue":114,"FORIN":115,"FOROF":116,"BY":117,"SWITCH":118,"Whens":119,"ELSE":120,"When":121,"LEADING_WHEN":122,"IfBlock":123,"IF":124,"POST_IF":125,"UNARY":126,"-":127,"+":128,"--":129,"++":130,"?":131,"MATH":132,"SHIFT":133,"COMPARE":134,"LOGIC":135,"RELATION":136,"COMPOUND_ASSIGN":137,"$accept":0,"$end":1}, +terminals_: {2:"error",6:"TERMINATOR",12:"STATEMENT",25:"INDENT",26:"OUTDENT",28:"IDENTIFIER",30:"NUMBER",31:"STRING",33:"JS",34:"REGEX",35:"DEBUGGER",36:"UNDEFINED",37:"NULL",38:"BOOL",40:"=",43:":",45:"RETURN",46:"HERECOMMENT",47:"PARAM_START",49:"PARAM_END",51:"->",52:"=>",54:",",57:"...",66:".",67:"?.",68:"::",70:"INDEX_START",72:"INDEX_END",73:"INDEX_SOAK",75:"{",77:"}",78:"CLASS",79:"EXTENDS",82:"SUPER",83:"FUNC_EXIST",84:"CALL_START",85:"CALL_END",87:"THIS",88:"@",89:"[",90:"]",92:"..",95:"TRY",97:"FINALLY",98:"CATCH",99:"THROW",100:"(",101:")",103:"WHILE",104:"WHEN",105:"UNTIL",107:"LOOP",109:"FOR",113:"OWN",115:"FORIN",116:"FOROF",117:"BY",118:"SWITCH",120:"ELSE",122:"LEADING_WHEN",124:"IF",125:"POST_IF",126:"UNARY",127:"-",128:"+",129:"--",130:"++",131:"?",132:"MATH",133:"SHIFT",134:"COMPARE",135:"LOGIC",136:"RELATION",137:"COMPOUND_ASSIGN"}, +productions_: [0,[3,0],[3,1],[3,2],[4,1],[4,3],[4,2],[7,1],[7,1],[9,1],[9,1],[9,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[5,2],[5,3],[27,1],[29,1],[29,1],[32,1],[32,1],[32,1],[32,1],[32,1],[32,1],[32,1],[17,3],[17,4],[17,5],[41,1],[41,3],[41,5],[41,1],[42,1],[42,1],[42,1],[10,2],[10,1],[11,1],[15,5],[15,2],[50,1],[50,1],[53,0],[53,1],[48,0],[48,1],[48,3],[48,4],[48,6],[55,1],[55,2],[55,3],[56,1],[56,1],[56,1],[56,1],[60,2],[61,1],[61,2],[61,2],[61,1],[39,1],[39,1],[39,1],[13,1],[13,1],[13,1],[13,1],[13,1],[62,2],[62,2],[62,2],[62,1],[62,1],[69,3],[69,2],[71,1],[71,1],[59,4],[76,0],[76,1],[76,3],[76,4],[76,6],[23,1],[23,2],[23,3],[23,4],[23,2],[23,3],[23,4],[23,5],[14,3],[14,3],[14,1],[14,2],[80,0],[80,1],[81,2],[81,4],[65,1],[65,1],[44,2],[58,2],[58,4],[91,1],[91,1],[64,5],[74,3],[74,2],[74,2],[74,1],[86,1],[86,3],[86,4],[86,4],[86,6],[93,1],[93,1],[94,1],[94,3],[19,2],[19,3],[19,4],[19,5],[96,3],[24,2],[63,3],[63,5],[102,2],[102,4],[102,2],[102,4],[20,2],[20,2],[20,2],[20,1],[106,2],[106,2],[21,2],[21,2],[21,2],[108,2],[108,2],[110,2],[110,3],[114,1],[114,1],[114,1],[114,1],[112,1],[112,3],[111,2],[111,2],[111,4],[111,4],[111,4],[111,6],[111,6],[22,5],[22,7],[22,4],[22,6],[119,1],[119,2],[121,3],[121,4],[123,3],[123,5],[18,1],[18,3],[18,3],[18,3],[16,2],[16,2],[16,2],[16,2],[16,2],[16,2],[16,2],[16,2],[16,3],[16,3],[16,3],[16,3],[16,3],[16,3],[16,3],[16,3],[16,5],[16,3]], +performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) { + +var $0 = $$.length - 1; +switch (yystate) { +case 1:return this.$ = new yy.Block; +break; +case 2:return this.$ = $$[$0]; +break; +case 3:return this.$ = $$[$0-1]; +break; +case 4:this.$ = yy.Block.wrap([$$[$0]]); +break; +case 5:this.$ = $$[$0-2].push($$[$0]); +break; +case 6:this.$ = $$[$0-1]; +break; +case 7:this.$ = $$[$0]; +break; +case 8:this.$ = $$[$0]; +break; +case 9:this.$ = $$[$0]; +break; +case 10:this.$ = $$[$0]; +break; +case 11:this.$ = new yy.Literal($$[$0]); +break; +case 12:this.$ = $$[$0]; +break; +case 13:this.$ = $$[$0]; +break; +case 14:this.$ = $$[$0]; +break; +case 15:this.$ = $$[$0]; +break; +case 16:this.$ = $$[$0]; +break; +case 17:this.$ = $$[$0]; +break; +case 18:this.$ = $$[$0]; +break; +case 19:this.$ = $$[$0]; +break; +case 20:this.$ = $$[$0]; +break; +case 21:this.$ = $$[$0]; +break; +case 22:this.$ = $$[$0]; +break; +case 23:this.$ = $$[$0]; +break; +case 24:this.$ = new yy.Block; +break; +case 25:this.$ = $$[$0-1]; +break; +case 26:this.$ = new yy.Literal($$[$0]); +break; +case 27:this.$ = new yy.Literal($$[$0]); +break; +case 28:this.$ = new yy.Literal($$[$0]); +break; +case 29:this.$ = $$[$0]; +break; +case 30:this.$ = new yy.Literal($$[$0]); +break; +case 31:this.$ = new yy.Literal($$[$0]); +break; +case 32:this.$ = new yy.Literal($$[$0]); +break; +case 33:this.$ = new yy.Undefined; +break; +case 34:this.$ = new yy.Null; +break; +case 35:this.$ = new yy.Bool($$[$0]); +break; +case 36:this.$ = new yy.Assign($$[$0-2], $$[$0]); +break; +case 37:this.$ = new yy.Assign($$[$0-3], $$[$0]); +break; +case 38:this.$ = new yy.Assign($$[$0-4], $$[$0-1]); +break; +case 39:this.$ = new yy.Value($$[$0]); +break; +case 40:this.$ = new yy.Assign(new yy.Value($$[$0-2]), $$[$0], 'object'); +break; +case 41:this.$ = new yy.Assign(new yy.Value($$[$0-4]), $$[$0-1], 'object'); +break; +case 42:this.$ = $$[$0]; +break; +case 43:this.$ = $$[$0]; +break; +case 44:this.$ = $$[$0]; +break; +case 45:this.$ = $$[$0]; +break; +case 46:this.$ = new yy.Return($$[$0]); +break; +case 47:this.$ = new yy.Return; +break; +case 48:this.$ = new yy.Comment($$[$0]); +break; +case 49:this.$ = new yy.Code($$[$0-3], $$[$0], $$[$0-1]); +break; +case 50:this.$ = new yy.Code([], $$[$0], $$[$0-1]); +break; +case 51:this.$ = 'func'; +break; +case 52:this.$ = 'boundfunc'; +break; +case 53:this.$ = $$[$0]; +break; +case 54:this.$ = $$[$0]; +break; +case 55:this.$ = []; +break; +case 56:this.$ = [$$[$0]]; +break; +case 57:this.$ = $$[$0-2].concat($$[$0]); +break; +case 58:this.$ = $$[$0-3].concat($$[$0]); +break; +case 59:this.$ = $$[$0-5].concat($$[$0-2]); +break; +case 60:this.$ = new yy.Param($$[$0]); +break; +case 61:this.$ = new yy.Param($$[$0-1], null, true); +break; +case 62:this.$ = new yy.Param($$[$0-2], $$[$0]); +break; +case 63:this.$ = $$[$0]; +break; +case 64:this.$ = $$[$0]; +break; +case 65:this.$ = $$[$0]; +break; +case 66:this.$ = $$[$0]; +break; +case 67:this.$ = new yy.Splat($$[$0-1]); +break; +case 68:this.$ = new yy.Value($$[$0]); +break; +case 69:this.$ = $$[$0-1].add($$[$0]); +break; +case 70:this.$ = new yy.Value($$[$0-1], [].concat($$[$0])); +break; +case 71:this.$ = $$[$0]; +break; +case 72:this.$ = $$[$0]; +break; +case 73:this.$ = new yy.Value($$[$0]); +break; +case 74:this.$ = new yy.Value($$[$0]); +break; +case 75:this.$ = $$[$0]; +break; +case 76:this.$ = new yy.Value($$[$0]); +break; +case 77:this.$ = new yy.Value($$[$0]); +break; +case 78:this.$ = new yy.Value($$[$0]); +break; +case 79:this.$ = $$[$0]; +break; +case 80:this.$ = new yy.Access($$[$0]); +break; +case 81:this.$ = new yy.Access($$[$0], 'soak'); +break; +case 82:this.$ = [new yy.Access(new yy.Literal('prototype')), new yy.Access($$[$0])]; +break; +case 83:this.$ = new yy.Access(new yy.Literal('prototype')); +break; +case 84:this.$ = $$[$0]; +break; +case 85:this.$ = $$[$0-1]; +break; +case 86:this.$ = yy.extend($$[$0], { + soak: true + }); +break; +case 87:this.$ = new yy.Index($$[$0]); +break; +case 88:this.$ = new yy.Slice($$[$0]); +break; +case 89:this.$ = new yy.Obj($$[$0-2], $$[$0-3].generated); +break; +case 90:this.$ = []; +break; +case 91:this.$ = [$$[$0]]; +break; +case 92:this.$ = $$[$0-2].concat($$[$0]); +break; +case 93:this.$ = $$[$0-3].concat($$[$0]); +break; +case 94:this.$ = $$[$0-5].concat($$[$0-2]); +break; +case 95:this.$ = new yy.Class; +break; +case 96:this.$ = new yy.Class(null, null, $$[$0]); +break; +case 97:this.$ = new yy.Class(null, $$[$0]); +break; +case 98:this.$ = new yy.Class(null, $$[$0-1], $$[$0]); +break; +case 99:this.$ = new yy.Class($$[$0]); +break; +case 100:this.$ = new yy.Class($$[$0-1], null, $$[$0]); +break; +case 101:this.$ = new yy.Class($$[$0-2], $$[$0]); +break; +case 102:this.$ = new yy.Class($$[$0-3], $$[$0-1], $$[$0]); +break; +case 103:this.$ = new yy.Call($$[$0-2], $$[$0], $$[$0-1]); +break; +case 104:this.$ = new yy.Call($$[$0-2], $$[$0], $$[$0-1]); +break; +case 105:this.$ = new yy.Call('super', [new yy.Splat(new yy.Literal('arguments'))]); +break; +case 106:this.$ = new yy.Call('super', $$[$0]); +break; +case 107:this.$ = false; +break; +case 108:this.$ = true; +break; +case 109:this.$ = []; +break; +case 110:this.$ = $$[$0-2]; +break; +case 111:this.$ = new yy.Value(new yy.Literal('this')); +break; +case 112:this.$ = new yy.Value(new yy.Literal('this')); +break; +case 113:this.$ = new yy.Value(new yy.Literal('this'), [new yy.Access($$[$0])], 'this'); +break; +case 114:this.$ = new yy.Arr([]); +break; +case 115:this.$ = new yy.Arr($$[$0-2]); +break; +case 116:this.$ = 'inclusive'; +break; +case 117:this.$ = 'exclusive'; +break; +case 118:this.$ = new yy.Range($$[$0-3], $$[$0-1], $$[$0-2]); +break; +case 119:this.$ = new yy.Range($$[$0-2], $$[$0], $$[$0-1]); +break; +case 120:this.$ = new yy.Range($$[$0-1], null, $$[$0]); +break; +case 121:this.$ = new yy.Range(null, $$[$0], $$[$0-1]); +break; +case 122:this.$ = new yy.Range(null, null, $$[$0]); +break; +case 123:this.$ = [$$[$0]]; +break; +case 124:this.$ = $$[$0-2].concat($$[$0]); +break; +case 125:this.$ = $$[$0-3].concat($$[$0]); +break; +case 126:this.$ = $$[$0-2]; +break; +case 127:this.$ = $$[$0-5].concat($$[$0-2]); +break; +case 128:this.$ = $$[$0]; +break; +case 129:this.$ = $$[$0]; +break; +case 130:this.$ = $$[$0]; +break; +case 131:this.$ = [].concat($$[$0-2], $$[$0]); +break; +case 132:this.$ = new yy.Try($$[$0]); +break; +case 133:this.$ = new yy.Try($$[$0-1], $$[$0][0], $$[$0][1]); +break; +case 134:this.$ = new yy.Try($$[$0-2], null, null, $$[$0]); +break; +case 135:this.$ = new yy.Try($$[$0-3], $$[$0-2][0], $$[$0-2][1], $$[$0]); +break; +case 136:this.$ = [$$[$0-1], $$[$0]]; +break; +case 137:this.$ = new yy.Throw($$[$0]); +break; +case 138:this.$ = new yy.Parens($$[$0-1]); +break; +case 139:this.$ = new yy.Parens($$[$0-2]); +break; +case 140:this.$ = new yy.While($$[$0]); +break; +case 141:this.$ = new yy.While($$[$0-2], { + guard: $$[$0] + }); +break; +case 142:this.$ = new yy.While($$[$0], { + invert: true + }); +break; +case 143:this.$ = new yy.While($$[$0-2], { + invert: true, + guard: $$[$0] + }); +break; +case 144:this.$ = $$[$0-1].addBody($$[$0]); +break; +case 145:this.$ = $$[$0].addBody(yy.Block.wrap([$$[$0-1]])); +break; +case 146:this.$ = $$[$0].addBody(yy.Block.wrap([$$[$0-1]])); +break; +case 147:this.$ = $$[$0]; +break; +case 148:this.$ = new yy.While(new yy.Literal('true')).addBody($$[$0]); +break; +case 149:this.$ = new yy.While(new yy.Literal('true')).addBody(yy.Block.wrap([$$[$0]])); +break; +case 150:this.$ = new yy.For($$[$0-1], $$[$0]); +break; +case 151:this.$ = new yy.For($$[$0-1], $$[$0]); +break; +case 152:this.$ = new yy.For($$[$0], $$[$0-1]); +break; +case 153:this.$ = { + source: new yy.Value($$[$0]) + }; +break; +case 154:this.$ = (function () { + $$[$0].own = $$[$0-1].own; + $$[$0].name = $$[$0-1][0]; + $$[$0].index = $$[$0-1][1]; + return $$[$0]; + }()); +break; +case 155:this.$ = $$[$0]; +break; +case 156:this.$ = (function () { + $$[$0].own = true; + return $$[$0]; + }()); +break; +case 157:this.$ = $$[$0]; +break; +case 158:this.$ = $$[$0]; +break; +case 159:this.$ = new yy.Value($$[$0]); +break; +case 160:this.$ = new yy.Value($$[$0]); +break; +case 161:this.$ = [$$[$0]]; +break; +case 162:this.$ = [$$[$0-2], $$[$0]]; +break; +case 163:this.$ = { + source: $$[$0] + }; +break; +case 164:this.$ = { + source: $$[$0], + object: true + }; +break; +case 165:this.$ = { + source: $$[$0-2], + guard: $$[$0] + }; +break; +case 166:this.$ = { + source: $$[$0-2], + guard: $$[$0], + object: true + }; +break; +case 167:this.$ = { + source: $$[$0-2], + step: $$[$0] + }; +break; +case 168:this.$ = { + source: $$[$0-4], + guard: $$[$0-2], + step: $$[$0] + }; +break; +case 169:this.$ = { + source: $$[$0-4], + step: $$[$0-2], + guard: $$[$0] + }; +break; +case 170:this.$ = new yy.Switch($$[$0-3], $$[$0-1]); +break; +case 171:this.$ = new yy.Switch($$[$0-5], $$[$0-3], $$[$0-1]); +break; +case 172:this.$ = new yy.Switch(null, $$[$0-1]); +break; +case 173:this.$ = new yy.Switch(null, $$[$0-3], $$[$0-1]); +break; +case 174:this.$ = $$[$0]; +break; +case 175:this.$ = $$[$0-1].concat($$[$0]); +break; +case 176:this.$ = [[$$[$0-1], $$[$0]]]; +break; +case 177:this.$ = [[$$[$0-2], $$[$0-1]]]; +break; +case 178:this.$ = new yy.If($$[$0-1], $$[$0], { + type: $$[$0-2] + }); +break; +case 179:this.$ = $$[$0-4].addElse(new yy.If($$[$0-1], $$[$0], { + type: $$[$0-2] + })); +break; +case 180:this.$ = $$[$0]; +break; +case 181:this.$ = $$[$0-2].addElse($$[$0]); +break; +case 182:this.$ = new yy.If($$[$0], yy.Block.wrap([$$[$0-2]]), { + type: $$[$0-1], + statement: true + }); +break; +case 183:this.$ = new yy.If($$[$0], yy.Block.wrap([$$[$0-2]]), { + type: $$[$0-1], + statement: true + }); +break; +case 184:this.$ = new yy.Op($$[$0-1], $$[$0]); +break; +case 185:this.$ = new yy.Op('-', $$[$0]); +break; +case 186:this.$ = new yy.Op('+', $$[$0]); +break; +case 187:this.$ = new yy.Op('--', $$[$0]); +break; +case 188:this.$ = new yy.Op('++', $$[$0]); +break; +case 189:this.$ = new yy.Op('--', $$[$0-1], null, true); +break; +case 190:this.$ = new yy.Op('++', $$[$0-1], null, true); +break; +case 191:this.$ = new yy.Existence($$[$0-1]); +break; +case 192:this.$ = new yy.Op('+', $$[$0-2], $$[$0]); +break; +case 193:this.$ = new yy.Op('-', $$[$0-2], $$[$0]); +break; +case 194:this.$ = new yy.Op($$[$0-1], $$[$0-2], $$[$0]); +break; +case 195:this.$ = new yy.Op($$[$0-1], $$[$0-2], $$[$0]); +break; +case 196:this.$ = new yy.Op($$[$0-1], $$[$0-2], $$[$0]); +break; +case 197:this.$ = new yy.Op($$[$0-1], $$[$0-2], $$[$0]); +break; +case 198:this.$ = (function () { + if ($$[$0-1].charAt(0) === '!') { + return new yy.Op($$[$0-1].slice(1), $$[$0-2], $$[$0]).invert(); + } else { + return new yy.Op($$[$0-1], $$[$0-2], $$[$0]); + } + }()); +break; +case 199:this.$ = new yy.Assign($$[$0-2], $$[$0], $$[$0-1]); +break; +case 200:this.$ = new yy.Assign($$[$0-4], $$[$0-1], $$[$0-3]); +break; +case 201:this.$ = new yy.Extends($$[$0-2], $$[$0]); +break; +} +}, +table: [{1:[2,1],3:1,4:2,5:3,7:4,8:6,9:7,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,5],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[3]},{1:[2,2],6:[1,74]},{6:[1,75]},{1:[2,4],6:[2,4],26:[2,4],101:[2,4]},{4:77,7:4,8:6,9:7,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,26:[1,76],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,7],6:[2,7],26:[2,7],101:[2,7],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,8],6:[2,8],26:[2,8],101:[2,8],102:90,103:[1,65],105:[1,66],108:91,109:[1,68],110:69,125:[1,89]},{1:[2,12],6:[2,12],25:[2,12],26:[2,12],49:[2,12],54:[2,12],57:[2,12],62:93,66:[1,95],67:[1,96],68:[1,97],69:98,70:[1,99],72:[2,12],73:[1,100],77:[2,12],80:92,83:[1,94],84:[2,107],85:[2,12],90:[2,12],92:[2,12],101:[2,12],103:[2,12],104:[2,12],105:[2,12],109:[2,12],117:[2,12],125:[2,12],127:[2,12],128:[2,12],131:[2,12],132:[2,12],133:[2,12],134:[2,12],135:[2,12],136:[2,12]},{1:[2,13],6:[2,13],25:[2,13],26:[2,13],49:[2,13],54:[2,13],57:[2,13],62:102,66:[1,95],67:[1,96],68:[1,97],69:98,70:[1,99],72:[2,13],73:[1,100],77:[2,13],80:101,83:[1,94],84:[2,107],85:[2,13],90:[2,13],92:[2,13],101:[2,13],103:[2,13],104:[2,13],105:[2,13],109:[2,13],117:[2,13],125:[2,13],127:[2,13],128:[2,13],131:[2,13],132:[2,13],133:[2,13],134:[2,13],135:[2,13],136:[2,13]},{1:[2,14],6:[2,14],25:[2,14],26:[2,14],49:[2,14],54:[2,14],57:[2,14],72:[2,14],77:[2,14],85:[2,14],90:[2,14],92:[2,14],101:[2,14],103:[2,14],104:[2,14],105:[2,14],109:[2,14],117:[2,14],125:[2,14],127:[2,14],128:[2,14],131:[2,14],132:[2,14],133:[2,14],134:[2,14],135:[2,14],136:[2,14]},{1:[2,15],6:[2,15],25:[2,15],26:[2,15],49:[2,15],54:[2,15],57:[2,15],72:[2,15],77:[2,15],85:[2,15],90:[2,15],92:[2,15],101:[2,15],103:[2,15],104:[2,15],105:[2,15],109:[2,15],117:[2,15],125:[2,15],127:[2,15],128:[2,15],131:[2,15],132:[2,15],133:[2,15],134:[2,15],135:[2,15],136:[2,15]},{1:[2,16],6:[2,16],25:[2,16],26:[2,16],49:[2,16],54:[2,16],57:[2,16],72:[2,16],77:[2,16],85:[2,16],90:[2,16],92:[2,16],101:[2,16],103:[2,16],104:[2,16],105:[2,16],109:[2,16],117:[2,16],125:[2,16],127:[2,16],128:[2,16],131:[2,16],132:[2,16],133:[2,16],134:[2,16],135:[2,16],136:[2,16]},{1:[2,17],6:[2,17],25:[2,17],26:[2,17],49:[2,17],54:[2,17],57:[2,17],72:[2,17],77:[2,17],85:[2,17],90:[2,17],92:[2,17],101:[2,17],103:[2,17],104:[2,17],105:[2,17],109:[2,17],117:[2,17],125:[2,17],127:[2,17],128:[2,17],131:[2,17],132:[2,17],133:[2,17],134:[2,17],135:[2,17],136:[2,17]},{1:[2,18],6:[2,18],25:[2,18],26:[2,18],49:[2,18],54:[2,18],57:[2,18],72:[2,18],77:[2,18],85:[2,18],90:[2,18],92:[2,18],101:[2,18],103:[2,18],104:[2,18],105:[2,18],109:[2,18],117:[2,18],125:[2,18],127:[2,18],128:[2,18],131:[2,18],132:[2,18],133:[2,18],134:[2,18],135:[2,18],136:[2,18]},{1:[2,19],6:[2,19],25:[2,19],26:[2,19],49:[2,19],54:[2,19],57:[2,19],72:[2,19],77:[2,19],85:[2,19],90:[2,19],92:[2,19],101:[2,19],103:[2,19],104:[2,19],105:[2,19],109:[2,19],117:[2,19],125:[2,19],127:[2,19],128:[2,19],131:[2,19],132:[2,19],133:[2,19],134:[2,19],135:[2,19],136:[2,19]},{1:[2,20],6:[2,20],25:[2,20],26:[2,20],49:[2,20],54:[2,20],57:[2,20],72:[2,20],77:[2,20],85:[2,20],90:[2,20],92:[2,20],101:[2,20],103:[2,20],104:[2,20],105:[2,20],109:[2,20],117:[2,20],125:[2,20],127:[2,20],128:[2,20],131:[2,20],132:[2,20],133:[2,20],134:[2,20],135:[2,20],136:[2,20]},{1:[2,21],6:[2,21],25:[2,21],26:[2,21],49:[2,21],54:[2,21],57:[2,21],72:[2,21],77:[2,21],85:[2,21],90:[2,21],92:[2,21],101:[2,21],103:[2,21],104:[2,21],105:[2,21],109:[2,21],117:[2,21],125:[2,21],127:[2,21],128:[2,21],131:[2,21],132:[2,21],133:[2,21],134:[2,21],135:[2,21],136:[2,21]},{1:[2,22],6:[2,22],25:[2,22],26:[2,22],49:[2,22],54:[2,22],57:[2,22],72:[2,22],77:[2,22],85:[2,22],90:[2,22],92:[2,22],101:[2,22],103:[2,22],104:[2,22],105:[2,22],109:[2,22],117:[2,22],125:[2,22],127:[2,22],128:[2,22],131:[2,22],132:[2,22],133:[2,22],134:[2,22],135:[2,22],136:[2,22]},{1:[2,23],6:[2,23],25:[2,23],26:[2,23],49:[2,23],54:[2,23],57:[2,23],72:[2,23],77:[2,23],85:[2,23],90:[2,23],92:[2,23],101:[2,23],103:[2,23],104:[2,23],105:[2,23],109:[2,23],117:[2,23],125:[2,23],127:[2,23],128:[2,23],131:[2,23],132:[2,23],133:[2,23],134:[2,23],135:[2,23],136:[2,23]},{1:[2,9],6:[2,9],26:[2,9],101:[2,9],103:[2,9],105:[2,9],109:[2,9],125:[2,9]},{1:[2,10],6:[2,10],26:[2,10],101:[2,10],103:[2,10],105:[2,10],109:[2,10],125:[2,10]},{1:[2,11],6:[2,11],26:[2,11],101:[2,11],103:[2,11],105:[2,11],109:[2,11],125:[2,11]},{1:[2,75],6:[2,75],25:[2,75],26:[2,75],40:[1,103],49:[2,75],54:[2,75],57:[2,75],66:[2,75],67:[2,75],68:[2,75],70:[2,75],72:[2,75],73:[2,75],77:[2,75],83:[2,75],84:[2,75],85:[2,75],90:[2,75],92:[2,75],101:[2,75],103:[2,75],104:[2,75],105:[2,75],109:[2,75],117:[2,75],125:[2,75],127:[2,75],128:[2,75],131:[2,75],132:[2,75],133:[2,75],134:[2,75],135:[2,75],136:[2,75]},{1:[2,76],6:[2,76],25:[2,76],26:[2,76],49:[2,76],54:[2,76],57:[2,76],66:[2,76],67:[2,76],68:[2,76],70:[2,76],72:[2,76],73:[2,76],77:[2,76],83:[2,76],84:[2,76],85:[2,76],90:[2,76],92:[2,76],101:[2,76],103:[2,76],104:[2,76],105:[2,76],109:[2,76],117:[2,76],125:[2,76],127:[2,76],128:[2,76],131:[2,76],132:[2,76],133:[2,76],134:[2,76],135:[2,76],136:[2,76]},{1:[2,77],6:[2,77],25:[2,77],26:[2,77],49:[2,77],54:[2,77],57:[2,77],66:[2,77],67:[2,77],68:[2,77],70:[2,77],72:[2,77],73:[2,77],77:[2,77],83:[2,77],84:[2,77],85:[2,77],90:[2,77],92:[2,77],101:[2,77],103:[2,77],104:[2,77],105:[2,77],109:[2,77],117:[2,77],125:[2,77],127:[2,77],128:[2,77],131:[2,77],132:[2,77],133:[2,77],134:[2,77],135:[2,77],136:[2,77]},{1:[2,78],6:[2,78],25:[2,78],26:[2,78],49:[2,78],54:[2,78],57:[2,78],66:[2,78],67:[2,78],68:[2,78],70:[2,78],72:[2,78],73:[2,78],77:[2,78],83:[2,78],84:[2,78],85:[2,78],90:[2,78],92:[2,78],101:[2,78],103:[2,78],104:[2,78],105:[2,78],109:[2,78],117:[2,78],125:[2,78],127:[2,78],128:[2,78],131:[2,78],132:[2,78],133:[2,78],134:[2,78],135:[2,78],136:[2,78]},{1:[2,79],6:[2,79],25:[2,79],26:[2,79],49:[2,79],54:[2,79],57:[2,79],66:[2,79],67:[2,79],68:[2,79],70:[2,79],72:[2,79],73:[2,79],77:[2,79],83:[2,79],84:[2,79],85:[2,79],90:[2,79],92:[2,79],101:[2,79],103:[2,79],104:[2,79],105:[2,79],109:[2,79],117:[2,79],125:[2,79],127:[2,79],128:[2,79],131:[2,79],132:[2,79],133:[2,79],134:[2,79],135:[2,79],136:[2,79]},{1:[2,105],6:[2,105],25:[2,105],26:[2,105],49:[2,105],54:[2,105],57:[2,105],66:[2,105],67:[2,105],68:[2,105],70:[2,105],72:[2,105],73:[2,105],77:[2,105],81:104,83:[2,105],84:[1,105],85:[2,105],90:[2,105],92:[2,105],101:[2,105],103:[2,105],104:[2,105],105:[2,105],109:[2,105],117:[2,105],125:[2,105],127:[2,105],128:[2,105],131:[2,105],132:[2,105],133:[2,105],134:[2,105],135:[2,105],136:[2,105]},{6:[2,55],25:[2,55],27:109,28:[1,73],44:110,48:106,49:[2,55],54:[2,55],55:107,56:108,58:111,59:112,75:[1,70],88:[1,113],89:[1,114]},{5:115,25:[1,5]},{8:116,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:118,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:119,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{13:121,14:122,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:123,44:63,58:47,59:48,61:120,63:25,64:26,65:27,75:[1,70],82:[1,28],87:[1,58],88:[1,59],89:[1,57],100:[1,56]},{13:121,14:122,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:123,44:63,58:47,59:48,61:124,63:25,64:26,65:27,75:[1,70],82:[1,28],87:[1,58],88:[1,59],89:[1,57],100:[1,56]},{1:[2,72],6:[2,72],25:[2,72],26:[2,72],40:[2,72],49:[2,72],54:[2,72],57:[2,72],66:[2,72],67:[2,72],68:[2,72],70:[2,72],72:[2,72],73:[2,72],77:[2,72],79:[1,128],83:[2,72],84:[2,72],85:[2,72],90:[2,72],92:[2,72],101:[2,72],103:[2,72],104:[2,72],105:[2,72],109:[2,72],117:[2,72],125:[2,72],127:[2,72],128:[2,72],129:[1,125],130:[1,126],131:[2,72],132:[2,72],133:[2,72],134:[2,72],135:[2,72],136:[2,72],137:[1,127]},{1:[2,180],6:[2,180],25:[2,180],26:[2,180],49:[2,180],54:[2,180],57:[2,180],72:[2,180],77:[2,180],85:[2,180],90:[2,180],92:[2,180],101:[2,180],103:[2,180],104:[2,180],105:[2,180],109:[2,180],117:[2,180],120:[1,129],125:[2,180],127:[2,180],128:[2,180],131:[2,180],132:[2,180],133:[2,180],134:[2,180],135:[2,180],136:[2,180]},{5:130,25:[1,5]},{5:131,25:[1,5]},{1:[2,147],6:[2,147],25:[2,147],26:[2,147],49:[2,147],54:[2,147],57:[2,147],72:[2,147],77:[2,147],85:[2,147],90:[2,147],92:[2,147],101:[2,147],103:[2,147],104:[2,147],105:[2,147],109:[2,147],117:[2,147],125:[2,147],127:[2,147],128:[2,147],131:[2,147],132:[2,147],133:[2,147],134:[2,147],135:[2,147],136:[2,147]},{5:132,25:[1,5]},{8:133,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,134],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,95],5:135,6:[2,95],13:121,14:122,25:[1,5],26:[2,95],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:123,44:63,49:[2,95],54:[2,95],57:[2,95],58:47,59:48,61:137,63:25,64:26,65:27,72:[2,95],75:[1,70],77:[2,95],79:[1,136],82:[1,28],85:[2,95],87:[1,58],88:[1,59],89:[1,57],90:[2,95],92:[2,95],100:[1,56],101:[2,95],103:[2,95],104:[2,95],105:[2,95],109:[2,95],117:[2,95],125:[2,95],127:[2,95],128:[2,95],131:[2,95],132:[2,95],133:[2,95],134:[2,95],135:[2,95],136:[2,95]},{8:138,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,47],6:[2,47],8:139,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,26:[2,47],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],101:[2,47],102:39,103:[2,47],105:[2,47],106:40,107:[1,67],108:41,109:[2,47],110:69,118:[1,42],123:37,124:[1,64],125:[2,47],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,48],6:[2,48],25:[2,48],26:[2,48],54:[2,48],77:[2,48],101:[2,48],103:[2,48],105:[2,48],109:[2,48],125:[2,48]},{1:[2,73],6:[2,73],25:[2,73],26:[2,73],40:[2,73],49:[2,73],54:[2,73],57:[2,73],66:[2,73],67:[2,73],68:[2,73],70:[2,73],72:[2,73],73:[2,73],77:[2,73],83:[2,73],84:[2,73],85:[2,73],90:[2,73],92:[2,73],101:[2,73],103:[2,73],104:[2,73],105:[2,73],109:[2,73],117:[2,73],125:[2,73],127:[2,73],128:[2,73],131:[2,73],132:[2,73],133:[2,73],134:[2,73],135:[2,73],136:[2,73]},{1:[2,74],6:[2,74],25:[2,74],26:[2,74],40:[2,74],49:[2,74],54:[2,74],57:[2,74],66:[2,74],67:[2,74],68:[2,74],70:[2,74],72:[2,74],73:[2,74],77:[2,74],83:[2,74],84:[2,74],85:[2,74],90:[2,74],92:[2,74],101:[2,74],103:[2,74],104:[2,74],105:[2,74],109:[2,74],117:[2,74],125:[2,74],127:[2,74],128:[2,74],131:[2,74],132:[2,74],133:[2,74],134:[2,74],135:[2,74],136:[2,74]},{1:[2,29],6:[2,29],25:[2,29],26:[2,29],49:[2,29],54:[2,29],57:[2,29],66:[2,29],67:[2,29],68:[2,29],70:[2,29],72:[2,29],73:[2,29],77:[2,29],83:[2,29],84:[2,29],85:[2,29],90:[2,29],92:[2,29],101:[2,29],103:[2,29],104:[2,29],105:[2,29],109:[2,29],117:[2,29],125:[2,29],127:[2,29],128:[2,29],131:[2,29],132:[2,29],133:[2,29],134:[2,29],135:[2,29],136:[2,29]},{1:[2,30],6:[2,30],25:[2,30],26:[2,30],49:[2,30],54:[2,30],57:[2,30],66:[2,30],67:[2,30],68:[2,30],70:[2,30],72:[2,30],73:[2,30],77:[2,30],83:[2,30],84:[2,30],85:[2,30],90:[2,30],92:[2,30],101:[2,30],103:[2,30],104:[2,30],105:[2,30],109:[2,30],117:[2,30],125:[2,30],127:[2,30],128:[2,30],131:[2,30],132:[2,30],133:[2,30],134:[2,30],135:[2,30],136:[2,30]},{1:[2,31],6:[2,31],25:[2,31],26:[2,31],49:[2,31],54:[2,31],57:[2,31],66:[2,31],67:[2,31],68:[2,31],70:[2,31],72:[2,31],73:[2,31],77:[2,31],83:[2,31],84:[2,31],85:[2,31],90:[2,31],92:[2,31],101:[2,31],103:[2,31],104:[2,31],105:[2,31],109:[2,31],117:[2,31],125:[2,31],127:[2,31],128:[2,31],131:[2,31],132:[2,31],133:[2,31],134:[2,31],135:[2,31],136:[2,31]},{1:[2,32],6:[2,32],25:[2,32],26:[2,32],49:[2,32],54:[2,32],57:[2,32],66:[2,32],67:[2,32],68:[2,32],70:[2,32],72:[2,32],73:[2,32],77:[2,32],83:[2,32],84:[2,32],85:[2,32],90:[2,32],92:[2,32],101:[2,32],103:[2,32],104:[2,32],105:[2,32],109:[2,32],117:[2,32],125:[2,32],127:[2,32],128:[2,32],131:[2,32],132:[2,32],133:[2,32],134:[2,32],135:[2,32],136:[2,32]},{1:[2,33],6:[2,33],25:[2,33],26:[2,33],49:[2,33],54:[2,33],57:[2,33],66:[2,33],67:[2,33],68:[2,33],70:[2,33],72:[2,33],73:[2,33],77:[2,33],83:[2,33],84:[2,33],85:[2,33],90:[2,33],92:[2,33],101:[2,33],103:[2,33],104:[2,33],105:[2,33],109:[2,33],117:[2,33],125:[2,33],127:[2,33],128:[2,33],131:[2,33],132:[2,33],133:[2,33],134:[2,33],135:[2,33],136:[2,33]},{1:[2,34],6:[2,34],25:[2,34],26:[2,34],49:[2,34],54:[2,34],57:[2,34],66:[2,34],67:[2,34],68:[2,34],70:[2,34],72:[2,34],73:[2,34],77:[2,34],83:[2,34],84:[2,34],85:[2,34],90:[2,34],92:[2,34],101:[2,34],103:[2,34],104:[2,34],105:[2,34],109:[2,34],117:[2,34],125:[2,34],127:[2,34],128:[2,34],131:[2,34],132:[2,34],133:[2,34],134:[2,34],135:[2,34],136:[2,34]},{1:[2,35],6:[2,35],25:[2,35],26:[2,35],49:[2,35],54:[2,35],57:[2,35],66:[2,35],67:[2,35],68:[2,35],70:[2,35],72:[2,35],73:[2,35],77:[2,35],83:[2,35],84:[2,35],85:[2,35],90:[2,35],92:[2,35],101:[2,35],103:[2,35],104:[2,35],105:[2,35],109:[2,35],117:[2,35],125:[2,35],127:[2,35],128:[2,35],131:[2,35],132:[2,35],133:[2,35],134:[2,35],135:[2,35],136:[2,35]},{4:140,7:4,8:6,9:7,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,141],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:142,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,146],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,60:147,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],86:144,87:[1,58],88:[1,59],89:[1,57],90:[1,143],93:145,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,111],6:[2,111],25:[2,111],26:[2,111],49:[2,111],54:[2,111],57:[2,111],66:[2,111],67:[2,111],68:[2,111],70:[2,111],72:[2,111],73:[2,111],77:[2,111],83:[2,111],84:[2,111],85:[2,111],90:[2,111],92:[2,111],101:[2,111],103:[2,111],104:[2,111],105:[2,111],109:[2,111],117:[2,111],125:[2,111],127:[2,111],128:[2,111],131:[2,111],132:[2,111],133:[2,111],134:[2,111],135:[2,111],136:[2,111]},{1:[2,112],6:[2,112],25:[2,112],26:[2,112],27:148,28:[1,73],49:[2,112],54:[2,112],57:[2,112],66:[2,112],67:[2,112],68:[2,112],70:[2,112],72:[2,112],73:[2,112],77:[2,112],83:[2,112],84:[2,112],85:[2,112],90:[2,112],92:[2,112],101:[2,112],103:[2,112],104:[2,112],105:[2,112],109:[2,112],117:[2,112],125:[2,112],127:[2,112],128:[2,112],131:[2,112],132:[2,112],133:[2,112],134:[2,112],135:[2,112],136:[2,112]},{25:[2,51]},{25:[2,52]},{1:[2,68],6:[2,68],25:[2,68],26:[2,68],40:[2,68],49:[2,68],54:[2,68],57:[2,68],66:[2,68],67:[2,68],68:[2,68],70:[2,68],72:[2,68],73:[2,68],77:[2,68],79:[2,68],83:[2,68],84:[2,68],85:[2,68],90:[2,68],92:[2,68],101:[2,68],103:[2,68],104:[2,68],105:[2,68],109:[2,68],117:[2,68],125:[2,68],127:[2,68],128:[2,68],129:[2,68],130:[2,68],131:[2,68],132:[2,68],133:[2,68],134:[2,68],135:[2,68],136:[2,68],137:[2,68]},{1:[2,71],6:[2,71],25:[2,71],26:[2,71],40:[2,71],49:[2,71],54:[2,71],57:[2,71],66:[2,71],67:[2,71],68:[2,71],70:[2,71],72:[2,71],73:[2,71],77:[2,71],79:[2,71],83:[2,71],84:[2,71],85:[2,71],90:[2,71],92:[2,71],101:[2,71],103:[2,71],104:[2,71],105:[2,71],109:[2,71],117:[2,71],125:[2,71],127:[2,71],128:[2,71],129:[2,71],130:[2,71],131:[2,71],132:[2,71],133:[2,71],134:[2,71],135:[2,71],136:[2,71],137:[2,71]},{8:149,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:150,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:151,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{5:152,8:153,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,5],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{27:158,28:[1,73],44:159,58:160,59:161,64:154,75:[1,70],88:[1,113],89:[1,57],112:155,113:[1,156],114:157},{111:162,115:[1,163],116:[1,164]},{6:[2,90],11:168,25:[2,90],27:169,28:[1,73],29:170,30:[1,71],31:[1,72],41:166,42:167,44:171,46:[1,46],54:[2,90],76:165,77:[2,90],88:[1,113]},{1:[2,27],6:[2,27],25:[2,27],26:[2,27],43:[2,27],49:[2,27],54:[2,27],57:[2,27],66:[2,27],67:[2,27],68:[2,27],70:[2,27],72:[2,27],73:[2,27],77:[2,27],83:[2,27],84:[2,27],85:[2,27],90:[2,27],92:[2,27],101:[2,27],103:[2,27],104:[2,27],105:[2,27],109:[2,27],117:[2,27],125:[2,27],127:[2,27],128:[2,27],131:[2,27],132:[2,27],133:[2,27],134:[2,27],135:[2,27],136:[2,27]},{1:[2,28],6:[2,28],25:[2,28],26:[2,28],43:[2,28],49:[2,28],54:[2,28],57:[2,28],66:[2,28],67:[2,28],68:[2,28],70:[2,28],72:[2,28],73:[2,28],77:[2,28],83:[2,28],84:[2,28],85:[2,28],90:[2,28],92:[2,28],101:[2,28],103:[2,28],104:[2,28],105:[2,28],109:[2,28],117:[2,28],125:[2,28],127:[2,28],128:[2,28],131:[2,28],132:[2,28],133:[2,28],134:[2,28],135:[2,28],136:[2,28]},{1:[2,26],6:[2,26],25:[2,26],26:[2,26],40:[2,26],43:[2,26],49:[2,26],54:[2,26],57:[2,26],66:[2,26],67:[2,26],68:[2,26],70:[2,26],72:[2,26],73:[2,26],77:[2,26],79:[2,26],83:[2,26],84:[2,26],85:[2,26],90:[2,26],92:[2,26],101:[2,26],103:[2,26],104:[2,26],105:[2,26],109:[2,26],115:[2,26],116:[2,26],117:[2,26],125:[2,26],127:[2,26],128:[2,26],129:[2,26],130:[2,26],131:[2,26],132:[2,26],133:[2,26],134:[2,26],135:[2,26],136:[2,26],137:[2,26]},{1:[2,6],6:[2,6],7:172,8:6,9:7,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,26:[2,6],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],101:[2,6],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,3]},{1:[2,24],6:[2,24],25:[2,24],26:[2,24],49:[2,24],54:[2,24],57:[2,24],72:[2,24],77:[2,24],85:[2,24],90:[2,24],92:[2,24],97:[2,24],98:[2,24],101:[2,24],103:[2,24],104:[2,24],105:[2,24],109:[2,24],117:[2,24],120:[2,24],122:[2,24],125:[2,24],127:[2,24],128:[2,24],131:[2,24],132:[2,24],133:[2,24],134:[2,24],135:[2,24],136:[2,24]},{6:[1,74],26:[1,173]},{1:[2,191],6:[2,191],25:[2,191],26:[2,191],49:[2,191],54:[2,191],57:[2,191],72:[2,191],77:[2,191],85:[2,191],90:[2,191],92:[2,191],101:[2,191],103:[2,191],104:[2,191],105:[2,191],109:[2,191],117:[2,191],125:[2,191],127:[2,191],128:[2,191],131:[2,191],132:[2,191],133:[2,191],134:[2,191],135:[2,191],136:[2,191]},{8:174,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:175,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:176,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:177,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:178,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:179,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:180,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:181,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,146],6:[2,146],25:[2,146],26:[2,146],49:[2,146],54:[2,146],57:[2,146],72:[2,146],77:[2,146],85:[2,146],90:[2,146],92:[2,146],101:[2,146],103:[2,146],104:[2,146],105:[2,146],109:[2,146],117:[2,146],125:[2,146],127:[2,146],128:[2,146],131:[2,146],132:[2,146],133:[2,146],134:[2,146],135:[2,146],136:[2,146]},{1:[2,151],6:[2,151],25:[2,151],26:[2,151],49:[2,151],54:[2,151],57:[2,151],72:[2,151],77:[2,151],85:[2,151],90:[2,151],92:[2,151],101:[2,151],103:[2,151],104:[2,151],105:[2,151],109:[2,151],117:[2,151],125:[2,151],127:[2,151],128:[2,151],131:[2,151],132:[2,151],133:[2,151],134:[2,151],135:[2,151],136:[2,151]},{8:182,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,145],6:[2,145],25:[2,145],26:[2,145],49:[2,145],54:[2,145],57:[2,145],72:[2,145],77:[2,145],85:[2,145],90:[2,145],92:[2,145],101:[2,145],103:[2,145],104:[2,145],105:[2,145],109:[2,145],117:[2,145],125:[2,145],127:[2,145],128:[2,145],131:[2,145],132:[2,145],133:[2,145],134:[2,145],135:[2,145],136:[2,145]},{1:[2,150],6:[2,150],25:[2,150],26:[2,150],49:[2,150],54:[2,150],57:[2,150],72:[2,150],77:[2,150],85:[2,150],90:[2,150],92:[2,150],101:[2,150],103:[2,150],104:[2,150],105:[2,150],109:[2,150],117:[2,150],125:[2,150],127:[2,150],128:[2,150],131:[2,150],132:[2,150],133:[2,150],134:[2,150],135:[2,150],136:[2,150]},{81:183,84:[1,105]},{1:[2,69],6:[2,69],25:[2,69],26:[2,69],40:[2,69],49:[2,69],54:[2,69],57:[2,69],66:[2,69],67:[2,69],68:[2,69],70:[2,69],72:[2,69],73:[2,69],77:[2,69],79:[2,69],83:[2,69],84:[2,69],85:[2,69],90:[2,69],92:[2,69],101:[2,69],103:[2,69],104:[2,69],105:[2,69],109:[2,69],117:[2,69],125:[2,69],127:[2,69],128:[2,69],129:[2,69],130:[2,69],131:[2,69],132:[2,69],133:[2,69],134:[2,69],135:[2,69],136:[2,69],137:[2,69]},{84:[2,108]},{27:184,28:[1,73]},{27:185,28:[1,73]},{1:[2,83],6:[2,83],25:[2,83],26:[2,83],27:186,28:[1,73],40:[2,83],49:[2,83],54:[2,83],57:[2,83],66:[2,83],67:[2,83],68:[2,83],70:[2,83],72:[2,83],73:[2,83],77:[2,83],79:[2,83],83:[2,83],84:[2,83],85:[2,83],90:[2,83],92:[2,83],101:[2,83],103:[2,83],104:[2,83],105:[2,83],109:[2,83],117:[2,83],125:[2,83],127:[2,83],128:[2,83],129:[2,83],130:[2,83],131:[2,83],132:[2,83],133:[2,83],134:[2,83],135:[2,83],136:[2,83],137:[2,83]},{1:[2,84],6:[2,84],25:[2,84],26:[2,84],40:[2,84],49:[2,84],54:[2,84],57:[2,84],66:[2,84],67:[2,84],68:[2,84],70:[2,84],72:[2,84],73:[2,84],77:[2,84],79:[2,84],83:[2,84],84:[2,84],85:[2,84],90:[2,84],92:[2,84],101:[2,84],103:[2,84],104:[2,84],105:[2,84],109:[2,84],117:[2,84],125:[2,84],127:[2,84],128:[2,84],129:[2,84],130:[2,84],131:[2,84],132:[2,84],133:[2,84],134:[2,84],135:[2,84],136:[2,84],137:[2,84]},{8:188,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],57:[1,192],58:47,59:48,61:36,63:25,64:26,65:27,71:187,74:189,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],91:190,92:[1,191],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{69:193,70:[1,99],73:[1,100]},{81:194,84:[1,105]},{1:[2,70],6:[2,70],25:[2,70],26:[2,70],40:[2,70],49:[2,70],54:[2,70],57:[2,70],66:[2,70],67:[2,70],68:[2,70],70:[2,70],72:[2,70],73:[2,70],77:[2,70],79:[2,70],83:[2,70],84:[2,70],85:[2,70],90:[2,70],92:[2,70],101:[2,70],103:[2,70],104:[2,70],105:[2,70],109:[2,70],117:[2,70],125:[2,70],127:[2,70],128:[2,70],129:[2,70],130:[2,70],131:[2,70],132:[2,70],133:[2,70],134:[2,70],135:[2,70],136:[2,70],137:[2,70]},{6:[1,196],8:195,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,197],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,106],6:[2,106],25:[2,106],26:[2,106],49:[2,106],54:[2,106],57:[2,106],66:[2,106],67:[2,106],68:[2,106],70:[2,106],72:[2,106],73:[2,106],77:[2,106],83:[2,106],84:[2,106],85:[2,106],90:[2,106],92:[2,106],101:[2,106],103:[2,106],104:[2,106],105:[2,106],109:[2,106],117:[2,106],125:[2,106],127:[2,106],128:[2,106],131:[2,106],132:[2,106],133:[2,106],134:[2,106],135:[2,106],136:[2,106]},{8:200,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,146],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,60:147,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],85:[1,198],86:199,87:[1,58],88:[1,59],89:[1,57],93:145,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[2,53],25:[2,53],49:[1,201],53:203,54:[1,202]},{6:[2,56],25:[2,56],26:[2,56],49:[2,56],54:[2,56]},{6:[2,60],25:[2,60],26:[2,60],40:[1,205],49:[2,60],54:[2,60],57:[1,204]},{6:[2,63],25:[2,63],26:[2,63],40:[2,63],49:[2,63],54:[2,63],57:[2,63]},{6:[2,64],25:[2,64],26:[2,64],40:[2,64],49:[2,64],54:[2,64],57:[2,64]},{6:[2,65],25:[2,65],26:[2,65],40:[2,65],49:[2,65],54:[2,65],57:[2,65]},{6:[2,66],25:[2,66],26:[2,66],40:[2,66],49:[2,66],54:[2,66],57:[2,66]},{27:148,28:[1,73]},{8:200,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,146],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,60:147,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],86:144,87:[1,58],88:[1,59],89:[1,57],90:[1,143],93:145,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,50],6:[2,50],25:[2,50],26:[2,50],49:[2,50],54:[2,50],57:[2,50],72:[2,50],77:[2,50],85:[2,50],90:[2,50],92:[2,50],101:[2,50],103:[2,50],104:[2,50],105:[2,50],109:[2,50],117:[2,50],125:[2,50],127:[2,50],128:[2,50],131:[2,50],132:[2,50],133:[2,50],134:[2,50],135:[2,50],136:[2,50]},{1:[2,184],6:[2,184],25:[2,184],26:[2,184],49:[2,184],54:[2,184],57:[2,184],72:[2,184],77:[2,184],85:[2,184],90:[2,184],92:[2,184],101:[2,184],102:87,103:[2,184],104:[2,184],105:[2,184],108:88,109:[2,184],110:69,117:[2,184],125:[2,184],127:[2,184],128:[2,184],131:[1,78],132:[2,184],133:[2,184],134:[2,184],135:[2,184],136:[2,184]},{102:90,103:[1,65],105:[1,66],108:91,109:[1,68],110:69,125:[1,89]},{1:[2,185],6:[2,185],25:[2,185],26:[2,185],49:[2,185],54:[2,185],57:[2,185],72:[2,185],77:[2,185],85:[2,185],90:[2,185],92:[2,185],101:[2,185],102:87,103:[2,185],104:[2,185],105:[2,185],108:88,109:[2,185],110:69,117:[2,185],125:[2,185],127:[2,185],128:[2,185],131:[1,78],132:[2,185],133:[2,185],134:[2,185],135:[2,185],136:[2,185]},{1:[2,186],6:[2,186],25:[2,186],26:[2,186],49:[2,186],54:[2,186],57:[2,186],72:[2,186],77:[2,186],85:[2,186],90:[2,186],92:[2,186],101:[2,186],102:87,103:[2,186],104:[2,186],105:[2,186],108:88,109:[2,186],110:69,117:[2,186],125:[2,186],127:[2,186],128:[2,186],131:[1,78],132:[2,186],133:[2,186],134:[2,186],135:[2,186],136:[2,186]},{1:[2,187],6:[2,187],25:[2,187],26:[2,187],49:[2,187],54:[2,187],57:[2,187],66:[2,72],67:[2,72],68:[2,72],70:[2,72],72:[2,187],73:[2,72],77:[2,187],83:[2,72],84:[2,72],85:[2,187],90:[2,187],92:[2,187],101:[2,187],103:[2,187],104:[2,187],105:[2,187],109:[2,187],117:[2,187],125:[2,187],127:[2,187],128:[2,187],131:[2,187],132:[2,187],133:[2,187],134:[2,187],135:[2,187],136:[2,187]},{62:93,66:[1,95],67:[1,96],68:[1,97],69:98,70:[1,99],73:[1,100],80:92,83:[1,94],84:[2,107]},{62:102,66:[1,95],67:[1,96],68:[1,97],69:98,70:[1,99],73:[1,100],80:101,83:[1,94],84:[2,107]},{66:[2,75],67:[2,75],68:[2,75],70:[2,75],73:[2,75],83:[2,75],84:[2,75]},{1:[2,188],6:[2,188],25:[2,188],26:[2,188],49:[2,188],54:[2,188],57:[2,188],66:[2,72],67:[2,72],68:[2,72],70:[2,72],72:[2,188],73:[2,72],77:[2,188],83:[2,72],84:[2,72],85:[2,188],90:[2,188],92:[2,188],101:[2,188],103:[2,188],104:[2,188],105:[2,188],109:[2,188],117:[2,188],125:[2,188],127:[2,188],128:[2,188],131:[2,188],132:[2,188],133:[2,188],134:[2,188],135:[2,188],136:[2,188]},{1:[2,189],6:[2,189],25:[2,189],26:[2,189],49:[2,189],54:[2,189],57:[2,189],72:[2,189],77:[2,189],85:[2,189],90:[2,189],92:[2,189],101:[2,189],103:[2,189],104:[2,189],105:[2,189],109:[2,189],117:[2,189],125:[2,189],127:[2,189],128:[2,189],131:[2,189],132:[2,189],133:[2,189],134:[2,189],135:[2,189],136:[2,189]},{1:[2,190],6:[2,190],25:[2,190],26:[2,190],49:[2,190],54:[2,190],57:[2,190],72:[2,190],77:[2,190],85:[2,190],90:[2,190],92:[2,190],101:[2,190],103:[2,190],104:[2,190],105:[2,190],109:[2,190],117:[2,190],125:[2,190],127:[2,190],128:[2,190],131:[2,190],132:[2,190],133:[2,190],134:[2,190],135:[2,190],136:[2,190]},{8:206,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,207],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:208,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{5:209,25:[1,5],124:[1,210]},{1:[2,132],6:[2,132],25:[2,132],26:[2,132],49:[2,132],54:[2,132],57:[2,132],72:[2,132],77:[2,132],85:[2,132],90:[2,132],92:[2,132],96:211,97:[1,212],98:[1,213],101:[2,132],103:[2,132],104:[2,132],105:[2,132],109:[2,132],117:[2,132],125:[2,132],127:[2,132],128:[2,132],131:[2,132],132:[2,132],133:[2,132],134:[2,132],135:[2,132],136:[2,132]},{1:[2,144],6:[2,144],25:[2,144],26:[2,144],49:[2,144],54:[2,144],57:[2,144],72:[2,144],77:[2,144],85:[2,144],90:[2,144],92:[2,144],101:[2,144],103:[2,144],104:[2,144],105:[2,144],109:[2,144],117:[2,144],125:[2,144],127:[2,144],128:[2,144],131:[2,144],132:[2,144],133:[2,144],134:[2,144],135:[2,144],136:[2,144]},{1:[2,152],6:[2,152],25:[2,152],26:[2,152],49:[2,152],54:[2,152],57:[2,152],72:[2,152],77:[2,152],85:[2,152],90:[2,152],92:[2,152],101:[2,152],103:[2,152],104:[2,152],105:[2,152],109:[2,152],117:[2,152],125:[2,152],127:[2,152],128:[2,152],131:[2,152],132:[2,152],133:[2,152],134:[2,152],135:[2,152],136:[2,152]},{25:[1,214],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{119:215,121:216,122:[1,217]},{1:[2,96],6:[2,96],25:[2,96],26:[2,96],49:[2,96],54:[2,96],57:[2,96],72:[2,96],77:[2,96],85:[2,96],90:[2,96],92:[2,96],101:[2,96],103:[2,96],104:[2,96],105:[2,96],109:[2,96],117:[2,96],125:[2,96],127:[2,96],128:[2,96],131:[2,96],132:[2,96],133:[2,96],134:[2,96],135:[2,96],136:[2,96]},{8:218,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,99],5:219,6:[2,99],25:[1,5],26:[2,99],49:[2,99],54:[2,99],57:[2,99],66:[2,72],67:[2,72],68:[2,72],70:[2,72],72:[2,99],73:[2,72],77:[2,99],79:[1,220],83:[2,72],84:[2,72],85:[2,99],90:[2,99],92:[2,99],101:[2,99],103:[2,99],104:[2,99],105:[2,99],109:[2,99],117:[2,99],125:[2,99],127:[2,99],128:[2,99],131:[2,99],132:[2,99],133:[2,99],134:[2,99],135:[2,99],136:[2,99]},{1:[2,137],6:[2,137],25:[2,137],26:[2,137],49:[2,137],54:[2,137],57:[2,137],72:[2,137],77:[2,137],85:[2,137],90:[2,137],92:[2,137],101:[2,137],102:87,103:[2,137],104:[2,137],105:[2,137],108:88,109:[2,137],110:69,117:[2,137],125:[2,137],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,46],6:[2,46],26:[2,46],101:[2,46],102:87,103:[2,46],105:[2,46],108:88,109:[2,46],110:69,125:[2,46],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{6:[1,74],101:[1,221]},{4:222,7:4,8:6,9:7,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[2,128],25:[2,128],54:[2,128],57:[1,224],90:[2,128],91:223,92:[1,191],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,114],6:[2,114],25:[2,114],26:[2,114],40:[2,114],49:[2,114],54:[2,114],57:[2,114],66:[2,114],67:[2,114],68:[2,114],70:[2,114],72:[2,114],73:[2,114],77:[2,114],83:[2,114],84:[2,114],85:[2,114],90:[2,114],92:[2,114],101:[2,114],103:[2,114],104:[2,114],105:[2,114],109:[2,114],115:[2,114],116:[2,114],117:[2,114],125:[2,114],127:[2,114],128:[2,114],131:[2,114],132:[2,114],133:[2,114],134:[2,114],135:[2,114],136:[2,114]},{6:[2,53],25:[2,53],53:225,54:[1,226],90:[2,53]},{6:[2,123],25:[2,123],26:[2,123],54:[2,123],85:[2,123],90:[2,123]},{8:200,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,146],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,60:147,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],86:227,87:[1,58],88:[1,59],89:[1,57],93:145,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[2,129],25:[2,129],26:[2,129],54:[2,129],85:[2,129],90:[2,129]},{1:[2,113],6:[2,113],25:[2,113],26:[2,113],40:[2,113],43:[2,113],49:[2,113],54:[2,113],57:[2,113],66:[2,113],67:[2,113],68:[2,113],70:[2,113],72:[2,113],73:[2,113],77:[2,113],79:[2,113],83:[2,113],84:[2,113],85:[2,113],90:[2,113],92:[2,113],101:[2,113],103:[2,113],104:[2,113],105:[2,113],109:[2,113],115:[2,113],116:[2,113],117:[2,113],125:[2,113],127:[2,113],128:[2,113],129:[2,113],130:[2,113],131:[2,113],132:[2,113],133:[2,113],134:[2,113],135:[2,113],136:[2,113],137:[2,113]},{5:228,25:[1,5],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,140],6:[2,140],25:[2,140],26:[2,140],49:[2,140],54:[2,140],57:[2,140],72:[2,140],77:[2,140],85:[2,140],90:[2,140],92:[2,140],101:[2,140],102:87,103:[1,65],104:[1,229],105:[1,66],108:88,109:[1,68],110:69,117:[2,140],125:[2,140],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,142],6:[2,142],25:[2,142],26:[2,142],49:[2,142],54:[2,142],57:[2,142],72:[2,142],77:[2,142],85:[2,142],90:[2,142],92:[2,142],101:[2,142],102:87,103:[1,65],104:[1,230],105:[1,66],108:88,109:[1,68],110:69,117:[2,142],125:[2,142],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,148],6:[2,148],25:[2,148],26:[2,148],49:[2,148],54:[2,148],57:[2,148],72:[2,148],77:[2,148],85:[2,148],90:[2,148],92:[2,148],101:[2,148],103:[2,148],104:[2,148],105:[2,148],109:[2,148],117:[2,148],125:[2,148],127:[2,148],128:[2,148],131:[2,148],132:[2,148],133:[2,148],134:[2,148],135:[2,148],136:[2,148]},{1:[2,149],6:[2,149],25:[2,149],26:[2,149],49:[2,149],54:[2,149],57:[2,149],72:[2,149],77:[2,149],85:[2,149],90:[2,149],92:[2,149],101:[2,149],102:87,103:[1,65],104:[2,149],105:[1,66],108:88,109:[1,68],110:69,117:[2,149],125:[2,149],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,153],6:[2,153],25:[2,153],26:[2,153],49:[2,153],54:[2,153],57:[2,153],72:[2,153],77:[2,153],85:[2,153],90:[2,153],92:[2,153],101:[2,153],103:[2,153],104:[2,153],105:[2,153],109:[2,153],117:[2,153],125:[2,153],127:[2,153],128:[2,153],131:[2,153],132:[2,153],133:[2,153],134:[2,153],135:[2,153],136:[2,153]},{115:[2,155],116:[2,155]},{27:158,28:[1,73],44:159,58:160,59:161,75:[1,70],88:[1,113],89:[1,114],112:231,114:157},{54:[1,232],115:[2,161],116:[2,161]},{54:[2,157],115:[2,157],116:[2,157]},{54:[2,158],115:[2,158],116:[2,158]},{54:[2,159],115:[2,159],116:[2,159]},{54:[2,160],115:[2,160],116:[2,160]},{1:[2,154],6:[2,154],25:[2,154],26:[2,154],49:[2,154],54:[2,154],57:[2,154],72:[2,154],77:[2,154],85:[2,154],90:[2,154],92:[2,154],101:[2,154],103:[2,154],104:[2,154],105:[2,154],109:[2,154],117:[2,154],125:[2,154],127:[2,154],128:[2,154],131:[2,154],132:[2,154],133:[2,154],134:[2,154],135:[2,154],136:[2,154]},{8:233,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:234,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[2,53],25:[2,53],53:235,54:[1,236],77:[2,53]},{6:[2,91],25:[2,91],26:[2,91],54:[2,91],77:[2,91]},{6:[2,39],25:[2,39],26:[2,39],43:[1,237],54:[2,39],77:[2,39]},{6:[2,42],25:[2,42],26:[2,42],54:[2,42],77:[2,42]},{6:[2,43],25:[2,43],26:[2,43],43:[2,43],54:[2,43],77:[2,43]},{6:[2,44],25:[2,44],26:[2,44],43:[2,44],54:[2,44],77:[2,44]},{6:[2,45],25:[2,45],26:[2,45],43:[2,45],54:[2,45],77:[2,45]},{1:[2,5],6:[2,5],26:[2,5],101:[2,5]},{1:[2,25],6:[2,25],25:[2,25],26:[2,25],49:[2,25],54:[2,25],57:[2,25],72:[2,25],77:[2,25],85:[2,25],90:[2,25],92:[2,25],97:[2,25],98:[2,25],101:[2,25],103:[2,25],104:[2,25],105:[2,25],109:[2,25],117:[2,25],120:[2,25],122:[2,25],125:[2,25],127:[2,25],128:[2,25],131:[2,25],132:[2,25],133:[2,25],134:[2,25],135:[2,25],136:[2,25]},{1:[2,192],6:[2,192],25:[2,192],26:[2,192],49:[2,192],54:[2,192],57:[2,192],72:[2,192],77:[2,192],85:[2,192],90:[2,192],92:[2,192],101:[2,192],102:87,103:[2,192],104:[2,192],105:[2,192],108:88,109:[2,192],110:69,117:[2,192],125:[2,192],127:[2,192],128:[2,192],131:[1,78],132:[1,81],133:[2,192],134:[2,192],135:[2,192],136:[2,192]},{1:[2,193],6:[2,193],25:[2,193],26:[2,193],49:[2,193],54:[2,193],57:[2,193],72:[2,193],77:[2,193],85:[2,193],90:[2,193],92:[2,193],101:[2,193],102:87,103:[2,193],104:[2,193],105:[2,193],108:88,109:[2,193],110:69,117:[2,193],125:[2,193],127:[2,193],128:[2,193],131:[1,78],132:[1,81],133:[2,193],134:[2,193],135:[2,193],136:[2,193]},{1:[2,194],6:[2,194],25:[2,194],26:[2,194],49:[2,194],54:[2,194],57:[2,194],72:[2,194],77:[2,194],85:[2,194],90:[2,194],92:[2,194],101:[2,194],102:87,103:[2,194],104:[2,194],105:[2,194],108:88,109:[2,194],110:69,117:[2,194],125:[2,194],127:[2,194],128:[2,194],131:[1,78],132:[2,194],133:[2,194],134:[2,194],135:[2,194],136:[2,194]},{1:[2,195],6:[2,195],25:[2,195],26:[2,195],49:[2,195],54:[2,195],57:[2,195],72:[2,195],77:[2,195],85:[2,195],90:[2,195],92:[2,195],101:[2,195],102:87,103:[2,195],104:[2,195],105:[2,195],108:88,109:[2,195],110:69,117:[2,195],125:[2,195],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[2,195],134:[2,195],135:[2,195],136:[2,195]},{1:[2,196],6:[2,196],25:[2,196],26:[2,196],49:[2,196],54:[2,196],57:[2,196],72:[2,196],77:[2,196],85:[2,196],90:[2,196],92:[2,196],101:[2,196],102:87,103:[2,196],104:[2,196],105:[2,196],108:88,109:[2,196],110:69,117:[2,196],125:[2,196],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[2,196],135:[2,196],136:[1,85]},{1:[2,197],6:[2,197],25:[2,197],26:[2,197],49:[2,197],54:[2,197],57:[2,197],72:[2,197],77:[2,197],85:[2,197],90:[2,197],92:[2,197],101:[2,197],102:87,103:[2,197],104:[2,197],105:[2,197],108:88,109:[2,197],110:69,117:[2,197],125:[2,197],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[2,197],136:[1,85]},{1:[2,198],6:[2,198],25:[2,198],26:[2,198],49:[2,198],54:[2,198],57:[2,198],72:[2,198],77:[2,198],85:[2,198],90:[2,198],92:[2,198],101:[2,198],102:87,103:[2,198],104:[2,198],105:[2,198],108:88,109:[2,198],110:69,117:[2,198],125:[2,198],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[2,198],135:[2,198],136:[2,198]},{1:[2,183],6:[2,183],25:[2,183],26:[2,183],49:[2,183],54:[2,183],57:[2,183],72:[2,183],77:[2,183],85:[2,183],90:[2,183],92:[2,183],101:[2,183],102:87,103:[1,65],104:[2,183],105:[1,66],108:88,109:[1,68],110:69,117:[2,183],125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,182],6:[2,182],25:[2,182],26:[2,182],49:[2,182],54:[2,182],57:[2,182],72:[2,182],77:[2,182],85:[2,182],90:[2,182],92:[2,182],101:[2,182],102:87,103:[1,65],104:[2,182],105:[1,66],108:88,109:[1,68],110:69,117:[2,182],125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,103],6:[2,103],25:[2,103],26:[2,103],49:[2,103],54:[2,103],57:[2,103],66:[2,103],67:[2,103],68:[2,103],70:[2,103],72:[2,103],73:[2,103],77:[2,103],83:[2,103],84:[2,103],85:[2,103],90:[2,103],92:[2,103],101:[2,103],103:[2,103],104:[2,103],105:[2,103],109:[2,103],117:[2,103],125:[2,103],127:[2,103],128:[2,103],131:[2,103],132:[2,103],133:[2,103],134:[2,103],135:[2,103],136:[2,103]},{1:[2,80],6:[2,80],25:[2,80],26:[2,80],40:[2,80],49:[2,80],54:[2,80],57:[2,80],66:[2,80],67:[2,80],68:[2,80],70:[2,80],72:[2,80],73:[2,80],77:[2,80],79:[2,80],83:[2,80],84:[2,80],85:[2,80],90:[2,80],92:[2,80],101:[2,80],103:[2,80],104:[2,80],105:[2,80],109:[2,80],117:[2,80],125:[2,80],127:[2,80],128:[2,80],129:[2,80],130:[2,80],131:[2,80],132:[2,80],133:[2,80],134:[2,80],135:[2,80],136:[2,80],137:[2,80]},{1:[2,81],6:[2,81],25:[2,81],26:[2,81],40:[2,81],49:[2,81],54:[2,81],57:[2,81],66:[2,81],67:[2,81],68:[2,81],70:[2,81],72:[2,81],73:[2,81],77:[2,81],79:[2,81],83:[2,81],84:[2,81],85:[2,81],90:[2,81],92:[2,81],101:[2,81],103:[2,81],104:[2,81],105:[2,81],109:[2,81],117:[2,81],125:[2,81],127:[2,81],128:[2,81],129:[2,81],130:[2,81],131:[2,81],132:[2,81],133:[2,81],134:[2,81],135:[2,81],136:[2,81],137:[2,81]},{1:[2,82],6:[2,82],25:[2,82],26:[2,82],40:[2,82],49:[2,82],54:[2,82],57:[2,82],66:[2,82],67:[2,82],68:[2,82],70:[2,82],72:[2,82],73:[2,82],77:[2,82],79:[2,82],83:[2,82],84:[2,82],85:[2,82],90:[2,82],92:[2,82],101:[2,82],103:[2,82],104:[2,82],105:[2,82],109:[2,82],117:[2,82],125:[2,82],127:[2,82],128:[2,82],129:[2,82],130:[2,82],131:[2,82],132:[2,82],133:[2,82],134:[2,82],135:[2,82],136:[2,82],137:[2,82]},{72:[1,238]},{57:[1,192],72:[2,87],91:239,92:[1,191],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{72:[2,88]},{8:240,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,72:[2,122],75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{12:[2,116],28:[2,116],30:[2,116],31:[2,116],33:[2,116],34:[2,116],35:[2,116],36:[2,116],37:[2,116],38:[2,116],45:[2,116],46:[2,116],47:[2,116],51:[2,116],52:[2,116],72:[2,116],75:[2,116],78:[2,116],82:[2,116],87:[2,116],88:[2,116],89:[2,116],95:[2,116],99:[2,116],100:[2,116],103:[2,116],105:[2,116],107:[2,116],109:[2,116],118:[2,116],124:[2,116],126:[2,116],127:[2,116],128:[2,116],129:[2,116],130:[2,116]},{12:[2,117],28:[2,117],30:[2,117],31:[2,117],33:[2,117],34:[2,117],35:[2,117],36:[2,117],37:[2,117],38:[2,117],45:[2,117],46:[2,117],47:[2,117],51:[2,117],52:[2,117],72:[2,117],75:[2,117],78:[2,117],82:[2,117],87:[2,117],88:[2,117],89:[2,117],95:[2,117],99:[2,117],100:[2,117],103:[2,117],105:[2,117],107:[2,117],109:[2,117],118:[2,117],124:[2,117],126:[2,117],127:[2,117],128:[2,117],129:[2,117],130:[2,117]},{1:[2,86],6:[2,86],25:[2,86],26:[2,86],40:[2,86],49:[2,86],54:[2,86],57:[2,86],66:[2,86],67:[2,86],68:[2,86],70:[2,86],72:[2,86],73:[2,86],77:[2,86],79:[2,86],83:[2,86],84:[2,86],85:[2,86],90:[2,86],92:[2,86],101:[2,86],103:[2,86],104:[2,86],105:[2,86],109:[2,86],117:[2,86],125:[2,86],127:[2,86],128:[2,86],129:[2,86],130:[2,86],131:[2,86],132:[2,86],133:[2,86],134:[2,86],135:[2,86],136:[2,86],137:[2,86]},{1:[2,104],6:[2,104],25:[2,104],26:[2,104],49:[2,104],54:[2,104],57:[2,104],66:[2,104],67:[2,104],68:[2,104],70:[2,104],72:[2,104],73:[2,104],77:[2,104],83:[2,104],84:[2,104],85:[2,104],90:[2,104],92:[2,104],101:[2,104],103:[2,104],104:[2,104],105:[2,104],109:[2,104],117:[2,104],125:[2,104],127:[2,104],128:[2,104],131:[2,104],132:[2,104],133:[2,104],134:[2,104],135:[2,104],136:[2,104]},{1:[2,36],6:[2,36],25:[2,36],26:[2,36],49:[2,36],54:[2,36],57:[2,36],72:[2,36],77:[2,36],85:[2,36],90:[2,36],92:[2,36],101:[2,36],102:87,103:[2,36],104:[2,36],105:[2,36],108:88,109:[2,36],110:69,117:[2,36],125:[2,36],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{8:241,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:242,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,109],6:[2,109],25:[2,109],26:[2,109],49:[2,109],54:[2,109],57:[2,109],66:[2,109],67:[2,109],68:[2,109],70:[2,109],72:[2,109],73:[2,109],77:[2,109],83:[2,109],84:[2,109],85:[2,109],90:[2,109],92:[2,109],101:[2,109],103:[2,109],104:[2,109],105:[2,109],109:[2,109],117:[2,109],125:[2,109],127:[2,109],128:[2,109],131:[2,109],132:[2,109],133:[2,109],134:[2,109],135:[2,109],136:[2,109]},{6:[2,53],25:[2,53],53:243,54:[1,226],85:[2,53]},{6:[2,128],25:[2,128],26:[2,128],54:[2,128],57:[1,244],85:[2,128],90:[2,128],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{50:245,51:[1,60],52:[1,61]},{6:[2,54],25:[2,54],26:[2,54],27:109,28:[1,73],44:110,55:246,56:108,58:111,59:112,75:[1,70],88:[1,113],89:[1,114]},{6:[1,247],25:[1,248]},{6:[2,61],25:[2,61],26:[2,61],49:[2,61],54:[2,61]},{8:249,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,199],6:[2,199],25:[2,199],26:[2,199],49:[2,199],54:[2,199],57:[2,199],72:[2,199],77:[2,199],85:[2,199],90:[2,199],92:[2,199],101:[2,199],102:87,103:[2,199],104:[2,199],105:[2,199],108:88,109:[2,199],110:69,117:[2,199],125:[2,199],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{8:250,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,201],6:[2,201],25:[2,201],26:[2,201],49:[2,201],54:[2,201],57:[2,201],72:[2,201],77:[2,201],85:[2,201],90:[2,201],92:[2,201],101:[2,201],102:87,103:[2,201],104:[2,201],105:[2,201],108:88,109:[2,201],110:69,117:[2,201],125:[2,201],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,181],6:[2,181],25:[2,181],26:[2,181],49:[2,181],54:[2,181],57:[2,181],72:[2,181],77:[2,181],85:[2,181],90:[2,181],92:[2,181],101:[2,181],103:[2,181],104:[2,181],105:[2,181],109:[2,181],117:[2,181],125:[2,181],127:[2,181],128:[2,181],131:[2,181],132:[2,181],133:[2,181],134:[2,181],135:[2,181],136:[2,181]},{8:251,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,133],6:[2,133],25:[2,133],26:[2,133],49:[2,133],54:[2,133],57:[2,133],72:[2,133],77:[2,133],85:[2,133],90:[2,133],92:[2,133],97:[1,252],101:[2,133],103:[2,133],104:[2,133],105:[2,133],109:[2,133],117:[2,133],125:[2,133],127:[2,133],128:[2,133],131:[2,133],132:[2,133],133:[2,133],134:[2,133],135:[2,133],136:[2,133]},{5:253,25:[1,5]},{27:254,28:[1,73]},{119:255,121:216,122:[1,217]},{26:[1,256],120:[1,257],121:258,122:[1,217]},{26:[2,174],120:[2,174],122:[2,174]},{8:260,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],94:259,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,97],5:261,6:[2,97],25:[1,5],26:[2,97],49:[2,97],54:[2,97],57:[2,97],72:[2,97],77:[2,97],85:[2,97],90:[2,97],92:[2,97],101:[2,97],102:87,103:[1,65],104:[2,97],105:[1,66],108:88,109:[1,68],110:69,117:[2,97],125:[2,97],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,100],6:[2,100],25:[2,100],26:[2,100],49:[2,100],54:[2,100],57:[2,100],72:[2,100],77:[2,100],85:[2,100],90:[2,100],92:[2,100],101:[2,100],103:[2,100],104:[2,100],105:[2,100],109:[2,100],117:[2,100],125:[2,100],127:[2,100],128:[2,100],131:[2,100],132:[2,100],133:[2,100],134:[2,100],135:[2,100],136:[2,100]},{8:262,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,138],6:[2,138],25:[2,138],26:[2,138],49:[2,138],54:[2,138],57:[2,138],66:[2,138],67:[2,138],68:[2,138],70:[2,138],72:[2,138],73:[2,138],77:[2,138],83:[2,138],84:[2,138],85:[2,138],90:[2,138],92:[2,138],101:[2,138],103:[2,138],104:[2,138],105:[2,138],109:[2,138],117:[2,138],125:[2,138],127:[2,138],128:[2,138],131:[2,138],132:[2,138],133:[2,138],134:[2,138],135:[2,138],136:[2,138]},{6:[1,74],26:[1,263]},{8:264,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[2,67],12:[2,117],25:[2,67],28:[2,117],30:[2,117],31:[2,117],33:[2,117],34:[2,117],35:[2,117],36:[2,117],37:[2,117],38:[2,117],45:[2,117],46:[2,117],47:[2,117],51:[2,117],52:[2,117],54:[2,67],75:[2,117],78:[2,117],82:[2,117],87:[2,117],88:[2,117],89:[2,117],90:[2,67],95:[2,117],99:[2,117],100:[2,117],103:[2,117],105:[2,117],107:[2,117],109:[2,117],118:[2,117],124:[2,117],126:[2,117],127:[2,117],128:[2,117],129:[2,117],130:[2,117]},{6:[1,266],25:[1,267],90:[1,265]},{6:[2,54],8:200,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[2,54],26:[2,54],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,60:147,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],85:[2,54],87:[1,58],88:[1,59],89:[1,57],90:[2,54],93:268,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[2,53],25:[2,53],26:[2,53],53:269,54:[1,226]},{1:[2,178],6:[2,178],25:[2,178],26:[2,178],49:[2,178],54:[2,178],57:[2,178],72:[2,178],77:[2,178],85:[2,178],90:[2,178],92:[2,178],101:[2,178],103:[2,178],104:[2,178],105:[2,178],109:[2,178],117:[2,178],120:[2,178],125:[2,178],127:[2,178],128:[2,178],131:[2,178],132:[2,178],133:[2,178],134:[2,178],135:[2,178],136:[2,178]},{8:270,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:271,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{115:[2,156],116:[2,156]},{27:158,28:[1,73],44:159,58:160,59:161,75:[1,70],88:[1,113],89:[1,114],114:272},{1:[2,163],6:[2,163],25:[2,163],26:[2,163],49:[2,163],54:[2,163],57:[2,163],72:[2,163],77:[2,163],85:[2,163],90:[2,163],92:[2,163],101:[2,163],102:87,103:[2,163],104:[1,273],105:[2,163],108:88,109:[2,163],110:69,117:[1,274],125:[2,163],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,164],6:[2,164],25:[2,164],26:[2,164],49:[2,164],54:[2,164],57:[2,164],72:[2,164],77:[2,164],85:[2,164],90:[2,164],92:[2,164],101:[2,164],102:87,103:[2,164],104:[1,275],105:[2,164],108:88,109:[2,164],110:69,117:[2,164],125:[2,164],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{6:[1,277],25:[1,278],77:[1,276]},{6:[2,54],11:168,25:[2,54],26:[2,54],27:169,28:[1,73],29:170,30:[1,71],31:[1,72],41:279,42:167,44:171,46:[1,46],77:[2,54],88:[1,113]},{8:280,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,281],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,85],6:[2,85],25:[2,85],26:[2,85],40:[2,85],49:[2,85],54:[2,85],57:[2,85],66:[2,85],67:[2,85],68:[2,85],70:[2,85],72:[2,85],73:[2,85],77:[2,85],79:[2,85],83:[2,85],84:[2,85],85:[2,85],90:[2,85],92:[2,85],101:[2,85],103:[2,85],104:[2,85],105:[2,85],109:[2,85],117:[2,85],125:[2,85],127:[2,85],128:[2,85],129:[2,85],130:[2,85],131:[2,85],132:[2,85],133:[2,85],134:[2,85],135:[2,85],136:[2,85],137:[2,85]},{8:282,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,72:[2,120],75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{72:[2,121],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,37],6:[2,37],25:[2,37],26:[2,37],49:[2,37],54:[2,37],57:[2,37],72:[2,37],77:[2,37],85:[2,37],90:[2,37],92:[2,37],101:[2,37],102:87,103:[2,37],104:[2,37],105:[2,37],108:88,109:[2,37],110:69,117:[2,37],125:[2,37],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{26:[1,283],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{6:[1,266],25:[1,267],85:[1,284]},{6:[2,67],25:[2,67],26:[2,67],54:[2,67],85:[2,67],90:[2,67]},{5:285,25:[1,5]},{6:[2,57],25:[2,57],26:[2,57],49:[2,57],54:[2,57]},{27:109,28:[1,73],44:110,55:286,56:108,58:111,59:112,75:[1,70],88:[1,113],89:[1,114]},{6:[2,55],25:[2,55],26:[2,55],27:109,28:[1,73],44:110,48:287,54:[2,55],55:107,56:108,58:111,59:112,75:[1,70],88:[1,113],89:[1,114]},{6:[2,62],25:[2,62],26:[2,62],49:[2,62],54:[2,62],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{26:[1,288],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{5:289,25:[1,5],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{5:290,25:[1,5]},{1:[2,134],6:[2,134],25:[2,134],26:[2,134],49:[2,134],54:[2,134],57:[2,134],72:[2,134],77:[2,134],85:[2,134],90:[2,134],92:[2,134],101:[2,134],103:[2,134],104:[2,134],105:[2,134],109:[2,134],117:[2,134],125:[2,134],127:[2,134],128:[2,134],131:[2,134],132:[2,134],133:[2,134],134:[2,134],135:[2,134],136:[2,134]},{5:291,25:[1,5]},{26:[1,292],120:[1,293],121:258,122:[1,217]},{1:[2,172],6:[2,172],25:[2,172],26:[2,172],49:[2,172],54:[2,172],57:[2,172],72:[2,172],77:[2,172],85:[2,172],90:[2,172],92:[2,172],101:[2,172],103:[2,172],104:[2,172],105:[2,172],109:[2,172],117:[2,172],125:[2,172],127:[2,172],128:[2,172],131:[2,172],132:[2,172],133:[2,172],134:[2,172],135:[2,172],136:[2,172]},{5:294,25:[1,5]},{26:[2,175],120:[2,175],122:[2,175]},{5:295,25:[1,5],54:[1,296]},{25:[2,130],54:[2,130],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,98],6:[2,98],25:[2,98],26:[2,98],49:[2,98],54:[2,98],57:[2,98],72:[2,98],77:[2,98],85:[2,98],90:[2,98],92:[2,98],101:[2,98],103:[2,98],104:[2,98],105:[2,98],109:[2,98],117:[2,98],125:[2,98],127:[2,98],128:[2,98],131:[2,98],132:[2,98],133:[2,98],134:[2,98],135:[2,98],136:[2,98]},{1:[2,101],5:297,6:[2,101],25:[1,5],26:[2,101],49:[2,101],54:[2,101],57:[2,101],72:[2,101],77:[2,101],85:[2,101],90:[2,101],92:[2,101],101:[2,101],102:87,103:[1,65],104:[2,101],105:[1,66],108:88,109:[1,68],110:69,117:[2,101],125:[2,101],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{101:[1,298]},{90:[1,299],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,115],6:[2,115],25:[2,115],26:[2,115],40:[2,115],49:[2,115],54:[2,115],57:[2,115],66:[2,115],67:[2,115],68:[2,115],70:[2,115],72:[2,115],73:[2,115],77:[2,115],83:[2,115],84:[2,115],85:[2,115],90:[2,115],92:[2,115],101:[2,115],103:[2,115],104:[2,115],105:[2,115],109:[2,115],115:[2,115],116:[2,115],117:[2,115],125:[2,115],127:[2,115],128:[2,115],131:[2,115],132:[2,115],133:[2,115],134:[2,115],135:[2,115],136:[2,115]},{8:200,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,60:147,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],93:300,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:200,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,146],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,60:147,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],86:301,87:[1,58],88:[1,59],89:[1,57],93:145,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[2,124],25:[2,124],26:[2,124],54:[2,124],85:[2,124],90:[2,124]},{6:[1,266],25:[1,267],26:[1,302]},{1:[2,141],6:[2,141],25:[2,141],26:[2,141],49:[2,141],54:[2,141],57:[2,141],72:[2,141],77:[2,141],85:[2,141],90:[2,141],92:[2,141],101:[2,141],102:87,103:[1,65],104:[2,141],105:[1,66],108:88,109:[1,68],110:69,117:[2,141],125:[2,141],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,143],6:[2,143],25:[2,143],26:[2,143],49:[2,143],54:[2,143],57:[2,143],72:[2,143],77:[2,143],85:[2,143],90:[2,143],92:[2,143],101:[2,143],102:87,103:[1,65],104:[2,143],105:[1,66],108:88,109:[1,68],110:69,117:[2,143],125:[2,143],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{115:[2,162],116:[2,162]},{8:303,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:304,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:305,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,89],6:[2,89],25:[2,89],26:[2,89],40:[2,89],49:[2,89],54:[2,89],57:[2,89],66:[2,89],67:[2,89],68:[2,89],70:[2,89],72:[2,89],73:[2,89],77:[2,89],83:[2,89],84:[2,89],85:[2,89],90:[2,89],92:[2,89],101:[2,89],103:[2,89],104:[2,89],105:[2,89],109:[2,89],115:[2,89],116:[2,89],117:[2,89],125:[2,89],127:[2,89],128:[2,89],131:[2,89],132:[2,89],133:[2,89],134:[2,89],135:[2,89],136:[2,89]},{11:168,27:169,28:[1,73],29:170,30:[1,71],31:[1,72],41:306,42:167,44:171,46:[1,46],88:[1,113]},{6:[2,90],11:168,25:[2,90],26:[2,90],27:169,28:[1,73],29:170,30:[1,71],31:[1,72],41:166,42:167,44:171,46:[1,46],54:[2,90],76:307,88:[1,113]},{6:[2,92],25:[2,92],26:[2,92],54:[2,92],77:[2,92]},{6:[2,40],25:[2,40],26:[2,40],54:[2,40],77:[2,40],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{8:308,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{72:[2,119],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,38],6:[2,38],25:[2,38],26:[2,38],49:[2,38],54:[2,38],57:[2,38],72:[2,38],77:[2,38],85:[2,38],90:[2,38],92:[2,38],101:[2,38],103:[2,38],104:[2,38],105:[2,38],109:[2,38],117:[2,38],125:[2,38],127:[2,38],128:[2,38],131:[2,38],132:[2,38],133:[2,38],134:[2,38],135:[2,38],136:[2,38]},{1:[2,110],6:[2,110],25:[2,110],26:[2,110],49:[2,110],54:[2,110],57:[2,110],66:[2,110],67:[2,110],68:[2,110],70:[2,110],72:[2,110],73:[2,110],77:[2,110],83:[2,110],84:[2,110],85:[2,110],90:[2,110],92:[2,110],101:[2,110],103:[2,110],104:[2,110],105:[2,110],109:[2,110],117:[2,110],125:[2,110],127:[2,110],128:[2,110],131:[2,110],132:[2,110],133:[2,110],134:[2,110],135:[2,110],136:[2,110]},{1:[2,49],6:[2,49],25:[2,49],26:[2,49],49:[2,49],54:[2,49],57:[2,49],72:[2,49],77:[2,49],85:[2,49],90:[2,49],92:[2,49],101:[2,49],103:[2,49],104:[2,49],105:[2,49],109:[2,49],117:[2,49],125:[2,49],127:[2,49],128:[2,49],131:[2,49],132:[2,49],133:[2,49],134:[2,49],135:[2,49],136:[2,49]},{6:[2,58],25:[2,58],26:[2,58],49:[2,58],54:[2,58]},{6:[2,53],25:[2,53],26:[2,53],53:309,54:[1,202]},{1:[2,200],6:[2,200],25:[2,200],26:[2,200],49:[2,200],54:[2,200],57:[2,200],72:[2,200],77:[2,200],85:[2,200],90:[2,200],92:[2,200],101:[2,200],103:[2,200],104:[2,200],105:[2,200],109:[2,200],117:[2,200],125:[2,200],127:[2,200],128:[2,200],131:[2,200],132:[2,200],133:[2,200],134:[2,200],135:[2,200],136:[2,200]},{1:[2,179],6:[2,179],25:[2,179],26:[2,179],49:[2,179],54:[2,179],57:[2,179],72:[2,179],77:[2,179],85:[2,179],90:[2,179],92:[2,179],101:[2,179],103:[2,179],104:[2,179],105:[2,179],109:[2,179],117:[2,179],120:[2,179],125:[2,179],127:[2,179],128:[2,179],131:[2,179],132:[2,179],133:[2,179],134:[2,179],135:[2,179],136:[2,179]},{1:[2,135],6:[2,135],25:[2,135],26:[2,135],49:[2,135],54:[2,135],57:[2,135],72:[2,135],77:[2,135],85:[2,135],90:[2,135],92:[2,135],101:[2,135],103:[2,135],104:[2,135],105:[2,135],109:[2,135],117:[2,135],125:[2,135],127:[2,135],128:[2,135],131:[2,135],132:[2,135],133:[2,135],134:[2,135],135:[2,135],136:[2,135]},{1:[2,136],6:[2,136],25:[2,136],26:[2,136],49:[2,136],54:[2,136],57:[2,136],72:[2,136],77:[2,136],85:[2,136],90:[2,136],92:[2,136],97:[2,136],101:[2,136],103:[2,136],104:[2,136],105:[2,136],109:[2,136],117:[2,136],125:[2,136],127:[2,136],128:[2,136],131:[2,136],132:[2,136],133:[2,136],134:[2,136],135:[2,136],136:[2,136]},{1:[2,170],6:[2,170],25:[2,170],26:[2,170],49:[2,170],54:[2,170],57:[2,170],72:[2,170],77:[2,170],85:[2,170],90:[2,170],92:[2,170],101:[2,170],103:[2,170],104:[2,170],105:[2,170],109:[2,170],117:[2,170],125:[2,170],127:[2,170],128:[2,170],131:[2,170],132:[2,170],133:[2,170],134:[2,170],135:[2,170],136:[2,170]},{5:310,25:[1,5]},{26:[1,311]},{6:[1,312],26:[2,176],120:[2,176],122:[2,176]},{8:313,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,102],6:[2,102],25:[2,102],26:[2,102],49:[2,102],54:[2,102],57:[2,102],72:[2,102],77:[2,102],85:[2,102],90:[2,102],92:[2,102],101:[2,102],103:[2,102],104:[2,102],105:[2,102],109:[2,102],117:[2,102],125:[2,102],127:[2,102],128:[2,102],131:[2,102],132:[2,102],133:[2,102],134:[2,102],135:[2,102],136:[2,102]},{1:[2,139],6:[2,139],25:[2,139],26:[2,139],49:[2,139],54:[2,139],57:[2,139],66:[2,139],67:[2,139],68:[2,139],70:[2,139],72:[2,139],73:[2,139],77:[2,139],83:[2,139],84:[2,139],85:[2,139],90:[2,139],92:[2,139],101:[2,139],103:[2,139],104:[2,139],105:[2,139],109:[2,139],117:[2,139],125:[2,139],127:[2,139],128:[2,139],131:[2,139],132:[2,139],133:[2,139],134:[2,139],135:[2,139],136:[2,139]},{1:[2,118],6:[2,118],25:[2,118],26:[2,118],49:[2,118],54:[2,118],57:[2,118],66:[2,118],67:[2,118],68:[2,118],70:[2,118],72:[2,118],73:[2,118],77:[2,118],83:[2,118],84:[2,118],85:[2,118],90:[2,118],92:[2,118],101:[2,118],103:[2,118],104:[2,118],105:[2,118],109:[2,118],117:[2,118],125:[2,118],127:[2,118],128:[2,118],131:[2,118],132:[2,118],133:[2,118],134:[2,118],135:[2,118],136:[2,118]},{6:[2,125],25:[2,125],26:[2,125],54:[2,125],85:[2,125],90:[2,125]},{6:[2,53],25:[2,53],26:[2,53],53:314,54:[1,226]},{6:[2,126],25:[2,126],26:[2,126],54:[2,126],85:[2,126],90:[2,126]},{1:[2,165],6:[2,165],25:[2,165],26:[2,165],49:[2,165],54:[2,165],57:[2,165],72:[2,165],77:[2,165],85:[2,165],90:[2,165],92:[2,165],101:[2,165],102:87,103:[2,165],104:[2,165],105:[2,165],108:88,109:[2,165],110:69,117:[1,315],125:[2,165],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,167],6:[2,167],25:[2,167],26:[2,167],49:[2,167],54:[2,167],57:[2,167],72:[2,167],77:[2,167],85:[2,167],90:[2,167],92:[2,167],101:[2,167],102:87,103:[2,167],104:[1,316],105:[2,167],108:88,109:[2,167],110:69,117:[2,167],125:[2,167],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,166],6:[2,166],25:[2,166],26:[2,166],49:[2,166],54:[2,166],57:[2,166],72:[2,166],77:[2,166],85:[2,166],90:[2,166],92:[2,166],101:[2,166],102:87,103:[2,166],104:[2,166],105:[2,166],108:88,109:[2,166],110:69,117:[2,166],125:[2,166],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{6:[2,93],25:[2,93],26:[2,93],54:[2,93],77:[2,93]},{6:[2,53],25:[2,53],26:[2,53],53:317,54:[1,236]},{26:[1,318],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{6:[1,247],25:[1,248],26:[1,319]},{26:[1,320]},{1:[2,173],6:[2,173],25:[2,173],26:[2,173],49:[2,173],54:[2,173],57:[2,173],72:[2,173],77:[2,173],85:[2,173],90:[2,173],92:[2,173],101:[2,173],103:[2,173],104:[2,173],105:[2,173],109:[2,173],117:[2,173],125:[2,173],127:[2,173],128:[2,173],131:[2,173],132:[2,173],133:[2,173],134:[2,173],135:[2,173],136:[2,173]},{26:[2,177],120:[2,177],122:[2,177]},{25:[2,131],54:[2,131],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{6:[1,266],25:[1,267],26:[1,321]},{8:322,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:323,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[1,277],25:[1,278],26:[1,324]},{6:[2,41],25:[2,41],26:[2,41],54:[2,41],77:[2,41]},{6:[2,59],25:[2,59],26:[2,59],49:[2,59],54:[2,59]},{1:[2,171],6:[2,171],25:[2,171],26:[2,171],49:[2,171],54:[2,171],57:[2,171],72:[2,171],77:[2,171],85:[2,171],90:[2,171],92:[2,171],101:[2,171],103:[2,171],104:[2,171],105:[2,171],109:[2,171],117:[2,171],125:[2,171],127:[2,171],128:[2,171],131:[2,171],132:[2,171],133:[2,171],134:[2,171],135:[2,171],136:[2,171]},{6:[2,127],25:[2,127],26:[2,127],54:[2,127],85:[2,127],90:[2,127]},{1:[2,168],6:[2,168],25:[2,168],26:[2,168],49:[2,168],54:[2,168],57:[2,168],72:[2,168],77:[2,168],85:[2,168],90:[2,168],92:[2,168],101:[2,168],102:87,103:[2,168],104:[2,168],105:[2,168],108:88,109:[2,168],110:69,117:[2,168],125:[2,168],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,169],6:[2,169],25:[2,169],26:[2,169],49:[2,169],54:[2,169],57:[2,169],72:[2,169],77:[2,169],85:[2,169],90:[2,169],92:[2,169],101:[2,169],102:87,103:[2,169],104:[2,169],105:[2,169],108:88,109:[2,169],110:69,117:[2,169],125:[2,169],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{6:[2,94],25:[2,94],26:[2,94],54:[2,94],77:[2,94]}], +defaultActions: {60:[2,51],61:[2,52],75:[2,3],94:[2,108],189:[2,88]}, +parseError: function parseError(str, hash) { + throw new Error(str); +}, +parse: function parse(input) { + var self = this, + stack = [0], + vstack = [null], // semantic value stack + lstack = [], // location stack + table = this.table, + yytext = '', + yylineno = 0, + yyleng = 0, + recovering = 0, + TERROR = 2, + EOF = 1; + + //this.reductionCount = this.shiftCount = 0; + + this.lexer.setInput(input); + this.lexer.yy = this.yy; + this.yy.lexer = this.lexer; + if (typeof this.lexer.yylloc == 'undefined') + this.lexer.yylloc = {}; + var yyloc = this.lexer.yylloc; + lstack.push(yyloc); + + if (typeof this.yy.parseError === 'function') + this.parseError = this.yy.parseError; + + function popStack (n) { + stack.length = stack.length - 2*n; + vstack.length = vstack.length - n; + lstack.length = lstack.length - n; + } + + function lex() { + var token; + token = self.lexer.lex() || 1; // $end = 1 + // if token isn't its numeric value, convert + if (typeof token !== 'number') { + token = self.symbols_[token] || token; + } + return token; + } + + var symbol, preErrorSymbol, state, action, a, r, yyval={},p,len,newState, expected; + while (true) { + // retreive state number from top of stack + state = stack[stack.length-1]; + + // use default actions if available + if (this.defaultActions[state]) { + action = this.defaultActions[state]; + } else { + if (symbol == null) + symbol = lex(); + // read action for current state and first input + action = table[state] && table[state][symbol]; + } + + // handle parse error + _handle_error: + if (typeof action === 'undefined' || !action.length || !action[0]) { + + if (!recovering) { + // Report error + expected = []; + for (p in table[state]) if (this.terminals_[p] && p > 2) { + expected.push("'"+this.terminals_[p]+"'"); + } + var errStr = ''; + if (this.lexer.showPosition) { + errStr = 'Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+expected.join(', ') + ", got '" + this.terminals_[symbol]+ "'"; + } else { + errStr = 'Parse error on line '+(yylineno+1)+": Unexpected " + + (symbol == 1 /*EOF*/ ? "end of input" : + ("'"+(this.terminals_[symbol] || symbol)+"'")); + } + this.parseError(errStr, + {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected}); + } + + // just recovered from another error + if (recovering == 3) { + if (symbol == EOF) { + throw new Error(errStr || 'Parsing halted.'); + } + + // discard current lookahead and grab another + yyleng = this.lexer.yyleng; + yytext = this.lexer.yytext; + yylineno = this.lexer.yylineno; + yyloc = this.lexer.yylloc; + symbol = lex(); + } + + // try to recover from error + while (1) { + // check for error recovery rule in this state + if ((TERROR.toString()) in table[state]) { + break; + } + if (state == 0) { + throw new Error(errStr || 'Parsing halted.'); + } + popStack(1); + state = stack[stack.length-1]; + } + + preErrorSymbol = symbol; // save the lookahead token + symbol = TERROR; // insert generic error symbol as new lookahead + state = stack[stack.length-1]; + action = table[state] && table[state][TERROR]; + recovering = 3; // allow 3 real symbols to be shifted before reporting a new error + } + + // this shouldn't happen, unless resolve defaults are off + if (action[0] instanceof Array && action.length > 1) { + throw new Error('Parse Error: multiple actions possible at state: '+state+', token: '+symbol); + } + + switch (action[0]) { + + case 1: // shift + //this.shiftCount++; + + stack.push(symbol); + vstack.push(this.lexer.yytext); + lstack.push(this.lexer.yylloc); + stack.push(action[1]); // push state + symbol = null; + if (!preErrorSymbol) { // normal execution/no error + yyleng = this.lexer.yyleng; + yytext = this.lexer.yytext; + yylineno = this.lexer.yylineno; + yyloc = this.lexer.yylloc; + if (recovering > 0) + recovering--; + } else { // error just occurred, resume old lookahead f/ before error + symbol = preErrorSymbol; + preErrorSymbol = null; + } + break; + + case 2: // reduce + //this.reductionCount++; + + len = this.productions_[action[1]][1]; + + // perform semantic action + yyval.$ = vstack[vstack.length-len]; // default to $$ = $1 + // default location, uses first token for firsts, last for lasts + yyval._$ = { + first_line: lstack[lstack.length-(len||1)].first_line, + last_line: lstack[lstack.length-1].last_line, + first_column: lstack[lstack.length-(len||1)].first_column, + last_column: lstack[lstack.length-1].last_column + }; + r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack); + + if (typeof r !== 'undefined') { + return r; + } + + // pop off stack + if (len) { + stack = stack.slice(0,-1*len*2); + vstack = vstack.slice(0, -1*len); + lstack = lstack.slice(0, -1*len); + } + + stack.push(this.productions_[action[1]][0]); // push nonterminal (reduce) + vstack.push(yyval.$); + lstack.push(yyval._$); + // goto new state = table[STATE][NONTERMINAL] + newState = table[stack[stack.length-2]][stack[stack.length-1]]; + stack.push(newState); + break; + + case 3: // accept + return true; + } + + } + + return true; +}}; +undefined + +module.exports = parser; + + +}); \ No newline at end of file diff --git a/lib/ace/mode/coffee/parser_test.js b/lib/ace/mode/coffee/parser_test.js new file mode 100644 index 0000000000..6e06f844d7 --- /dev/null +++ b/lib/ace/mode/coffee/parser_test.js @@ -0,0 +1,61 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); +} + +define(function(require, exports, module) { +"use strict"; + +var assert = require("../../test/assertions"); +var coffee = require("../coffee/coffee-script"); + + +module.exports = { + + "test parse valid coffee script": function() { + coffee.parse("square = (x) -> x * x"); + }, + + "test parse invalid coffee script": function() { + try { + coffee.parse("a = 12 f"); + } catch (e) { + assert.ok((e + "").indexOf("Parse error on line 1: Unexpected 'IDENTIFIER'") >= 0); + } + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/lib/ace/mode/coffee/rewriter.js b/lib/ace/mode/coffee/rewriter.js new file mode 100644 index 0000000000..f500e3d5c1 --- /dev/null +++ b/lib/ace/mode/coffee/rewriter.js @@ -0,0 +1,376 @@ +/** + * Copyright (c) 2009-2012 Jeremy Ashkenas + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +define(function(require, exports, module) { +// Generated by CoffeeScript 1.3.3 + + var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, SINGLE_CLOSERS, SINGLE_LINERS, left, rite, _i, _len, _ref, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, + __slice = [].slice; + + exports.Rewriter = (function() { + + function Rewriter() {} + + Rewriter.prototype.rewrite = function(tokens) { + this.tokens = tokens; + this.removeLeadingNewlines(); + this.removeMidExpressionNewlines(); + this.closeOpenCalls(); + this.closeOpenIndexes(); + this.addImplicitIndentation(); + this.tagPostfixConditionals(); + this.addImplicitBraces(); + this.addImplicitParentheses(); + return this.tokens; + }; + + Rewriter.prototype.scanTokens = function(block) { + var i, token, tokens; + tokens = this.tokens; + i = 0; + while (token = tokens[i]) { + i += block.call(this, token, i, tokens); + } + return true; + }; + + Rewriter.prototype.detectEnd = function(i, condition, action) { + var levels, token, tokens, _ref, _ref1; + tokens = this.tokens; + levels = 0; + while (token = tokens[i]) { + if (levels === 0 && condition.call(this, token, i)) { + return action.call(this, token, i); + } + if (!token || levels < 0) { + return action.call(this, token, i - 1); + } + if (_ref = token[0], __indexOf.call(EXPRESSION_START, _ref) >= 0) { + levels += 1; + } else if (_ref1 = token[0], __indexOf.call(EXPRESSION_END, _ref1) >= 0) { + levels -= 1; + } + i += 1; + } + return i - 1; + }; + + Rewriter.prototype.removeLeadingNewlines = function() { + var i, tag, _i, _len, _ref; + _ref = this.tokens; + for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { + tag = _ref[i][0]; + if (tag !== 'TERMINATOR') { + break; + } + } + if (i) { + return this.tokens.splice(0, i); + } + }; + + Rewriter.prototype.removeMidExpressionNewlines = function() { + return this.scanTokens(function(token, i, tokens) { + var _ref; + if (!(token[0] === 'TERMINATOR' && (_ref = this.tag(i + 1), __indexOf.call(EXPRESSION_CLOSE, _ref) >= 0))) { + return 1; + } + tokens.splice(i, 1); + return 0; + }); + }; + + Rewriter.prototype.closeOpenCalls = function() { + var action, condition; + condition = function(token, i) { + var _ref; + return ((_ref = token[0]) === ')' || _ref === 'CALL_END') || token[0] === 'OUTDENT' && this.tag(i - 1) === ')'; + }; + action = function(token, i) { + return this.tokens[token[0] === 'OUTDENT' ? i - 1 : i][0] = 'CALL_END'; + }; + return this.scanTokens(function(token, i) { + if (token[0] === 'CALL_START') { + this.detectEnd(i + 1, condition, action); + } + return 1; + }); + }; + + Rewriter.prototype.closeOpenIndexes = function() { + var action, condition; + condition = function(token, i) { + var _ref; + return (_ref = token[0]) === ']' || _ref === 'INDEX_END'; + }; + action = function(token, i) { + return token[0] = 'INDEX_END'; + }; + return this.scanTokens(function(token, i) { + if (token[0] === 'INDEX_START') { + this.detectEnd(i + 1, condition, action); + } + return 1; + }); + }; + + Rewriter.prototype.addImplicitBraces = function() { + var action, condition, sameLine, stack, start, startIndent, startIndex, startsLine; + stack = []; + start = null; + startsLine = null; + sameLine = true; + startIndent = 0; + startIndex = 0; + condition = function(token, i) { + var one, tag, three, two, _ref, _ref1; + _ref = this.tokens.slice(i + 1, +(i + 3) + 1 || 9e9), one = _ref[0], two = _ref[1], three = _ref[2]; + if ('HERECOMMENT' === (one != null ? one[0] : void 0)) { + return false; + } + tag = token[0]; + if (__indexOf.call(LINEBREAKS, tag) >= 0) { + sameLine = false; + } + return (((tag === 'TERMINATOR' || tag === 'OUTDENT') || (__indexOf.call(IMPLICIT_END, tag) >= 0 && sameLine && !(i - startIndex === 1))) && ((!startsLine && this.tag(i - 1) !== ',') || !((two != null ? two[0] : void 0) === ':' || (one != null ? one[0] : void 0) === '@' && (three != null ? three[0] : void 0) === ':'))) || (tag === ',' && one && ((_ref1 = one[0]) !== 'IDENTIFIER' && _ref1 !== 'NUMBER' && _ref1 !== 'STRING' && _ref1 !== '@' && _ref1 !== 'TERMINATOR' && _ref1 !== 'OUTDENT')); + }; + action = function(token, i) { + var tok; + tok = this.generate('}', '}', token[2]); + return this.tokens.splice(i, 0, tok); + }; + return this.scanTokens(function(token, i, tokens) { + var ago, idx, prevTag, tag, tok, value, _ref, _ref1; + if (_ref = (tag = token[0]), __indexOf.call(EXPRESSION_START, _ref) >= 0) { + stack.push([(tag === 'INDENT' && this.tag(i - 1) === '{' ? '{' : tag), i]); + return 1; + } + if (__indexOf.call(EXPRESSION_END, tag) >= 0) { + start = stack.pop(); + return 1; + } + if (!(tag === ':' && ((ago = this.tag(i - 2)) === ':' || ((_ref1 = stack[stack.length - 1]) != null ? _ref1[0] : void 0) !== '{'))) { + return 1; + } + sameLine = true; + startIndex = i + 1; + stack.push(['{']); + idx = ago === '@' ? i - 2 : i - 1; + while (this.tag(idx - 2) === 'HERECOMMENT') { + idx -= 2; + } + prevTag = this.tag(idx - 1); + startsLine = !prevTag || (__indexOf.call(LINEBREAKS, prevTag) >= 0); + value = new String('{'); + value.generated = true; + tok = this.generate('{', value, token[2]); + tokens.splice(idx, 0, tok); + this.detectEnd(i + 2, condition, action); + return 2; + }); + }; + + Rewriter.prototype.addImplicitParentheses = function() { + var action, condition, noCall, seenControl, seenSingle; + noCall = seenSingle = seenControl = false; + condition = function(token, i) { + var post, tag, _ref, _ref1; + tag = token[0]; + if (!seenSingle && token.fromThen) { + return true; + } + if (tag === 'IF' || tag === 'ELSE' || tag === 'CATCH' || tag === '->' || tag === '=>' || tag === 'CLASS') { + seenSingle = true; + } + if (tag === 'IF' || tag === 'ELSE' || tag === 'SWITCH' || tag === 'TRY' || tag === '=') { + seenControl = true; + } + if ((tag === '.' || tag === '?.' || tag === '::') && this.tag(i - 1) === 'OUTDENT') { + return true; + } + return !token.generated && this.tag(i - 1) !== ',' && (__indexOf.call(IMPLICIT_END, tag) >= 0 || (tag === 'INDENT' && !seenControl)) && (tag !== 'INDENT' || (((_ref = this.tag(i - 2)) !== 'CLASS' && _ref !== 'EXTENDS') && (_ref1 = this.tag(i - 1), __indexOf.call(IMPLICIT_BLOCK, _ref1) < 0) && !((post = this.tokens[i + 1]) && post.generated && post[0] === '{'))); + }; + action = function(token, i) { + return this.tokens.splice(i, 0, this.generate('CALL_END', ')', token[2])); + }; + return this.scanTokens(function(token, i, tokens) { + var callObject, current, next, prev, tag, _ref, _ref1, _ref2; + tag = token[0]; + if (tag === 'CLASS' || tag === 'IF' || tag === 'FOR' || tag === 'WHILE') { + noCall = true; + } + _ref = tokens.slice(i - 1, +(i + 1) + 1 || 9e9), prev = _ref[0], current = _ref[1], next = _ref[2]; + callObject = !noCall && tag === 'INDENT' && next && next.generated && next[0] === '{' && prev && (_ref1 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref1) >= 0); + seenSingle = false; + seenControl = false; + if (__indexOf.call(LINEBREAKS, tag) >= 0) { + noCall = false; + } + if (prev && !prev.spaced && tag === '?') { + token.call = true; + } + if (token.fromThen) { + return 1; + } + if (!(callObject || (prev != null ? prev.spaced : void 0) && (prev.call || (_ref2 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref2) >= 0)) && (__indexOf.call(IMPLICIT_CALL, tag) >= 0 || !(token.spaced || token.newLine) && __indexOf.call(IMPLICIT_UNSPACED_CALL, tag) >= 0))) { + return 1; + } + tokens.splice(i, 0, this.generate('CALL_START', '(', token[2])); + this.detectEnd(i + 1, condition, action); + if (prev[0] === '?') { + prev[0] = 'FUNC_EXIST'; + } + return 2; + }); + }; + + Rewriter.prototype.addImplicitIndentation = function() { + var action, condition, indent, outdent, starter; + starter = indent = outdent = null; + condition = function(token, i) { + var _ref; + return token[1] !== ';' && (_ref = token[0], __indexOf.call(SINGLE_CLOSERS, _ref) >= 0) && !(token[0] === 'ELSE' && (starter !== 'IF' && starter !== 'THEN')); + }; + action = function(token, i) { + return this.tokens.splice((this.tag(i - 1) === ',' ? i - 1 : i), 0, outdent); + }; + return this.scanTokens(function(token, i, tokens) { + var tag, _ref, _ref1; + tag = token[0]; + if (tag === 'TERMINATOR' && this.tag(i + 1) === 'THEN') { + tokens.splice(i, 1); + return 0; + } + if (tag === 'ELSE' && this.tag(i - 1) !== 'OUTDENT') { + tokens.splice.apply(tokens, [i, 0].concat(__slice.call(this.indentation(token)))); + return 2; + } + if (tag === 'CATCH' && ((_ref = this.tag(i + 2)) === 'OUTDENT' || _ref === 'TERMINATOR' || _ref === 'FINALLY')) { + tokens.splice.apply(tokens, [i + 2, 0].concat(__slice.call(this.indentation(token)))); + return 4; + } + if (__indexOf.call(SINGLE_LINERS, tag) >= 0 && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF')) { + starter = tag; + _ref1 = this.indentation(token, true), indent = _ref1[0], outdent = _ref1[1]; + if (starter === 'THEN') { + indent.fromThen = true; + } + tokens.splice(i + 1, 0, indent); + this.detectEnd(i + 2, condition, action); + if (tag === 'THEN') { + tokens.splice(i, 1); + } + return 1; + } + return 1; + }); + }; + + Rewriter.prototype.tagPostfixConditionals = function() { + var action, condition, original; + original = null; + condition = function(token, i) { + var _ref; + return (_ref = token[0]) === 'TERMINATOR' || _ref === 'INDENT'; + }; + action = function(token, i) { + if (token[0] !== 'INDENT' || (token.generated && !token.fromThen)) { + return original[0] = 'POST_' + original[0]; + } + }; + return this.scanTokens(function(token, i) { + if (token[0] !== 'IF') { + return 1; + } + original = token; + this.detectEnd(i + 1, condition, action); + return 1; + }); + }; + + Rewriter.prototype.indentation = function(token, implicit) { + var indent, outdent; + if (implicit == null) { + implicit = false; + } + indent = ['INDENT', 2, token[2]]; + outdent = ['OUTDENT', 2, token[2]]; + if (implicit) { + indent.generated = outdent.generated = true; + } + return [indent, outdent]; + }; + + Rewriter.prototype.generate = function(tag, value, line) { + var tok; + tok = [tag, value, line]; + tok.generated = true; + return tok; + }; + + Rewriter.prototype.tag = function(i) { + var _ref; + return (_ref = this.tokens[i]) != null ? _ref[0] : void 0; + }; + + return Rewriter; + + })(); + + BALANCED_PAIRS = [['(', ')'], ['[', ']'], ['{', '}'], ['INDENT', 'OUTDENT'], ['CALL_START', 'CALL_END'], ['PARAM_START', 'PARAM_END'], ['INDEX_START', 'INDEX_END']]; + + exports.INVERSES = INVERSES = {}; + + EXPRESSION_START = []; + + EXPRESSION_END = []; + + for (_i = 0, _len = BALANCED_PAIRS.length; _i < _len; _i++) { + _ref = BALANCED_PAIRS[_i], left = _ref[0], rite = _ref[1]; + EXPRESSION_START.push(INVERSES[rite] = left); + EXPRESSION_END.push(INVERSES[left] = rite); + } + + EXPRESSION_CLOSE = ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_END); + + IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS']; + + IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS', 'IF', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'NULL', 'UNDEFINED', 'UNARY', 'SUPER', '@', '->', '=>', '[', '(', '{', '--', '++']; + + IMPLICIT_UNSPACED_CALL = ['+', '-']; + + IMPLICIT_BLOCK = ['->', '=>', '{', '[', ',']; + + IMPLICIT_END = ['POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR']; + + SINGLE_LINERS = ['ELSE', '->', '=>', 'TRY', 'FINALLY', 'THEN']; + + SINGLE_CLOSERS = ['TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADING_WHEN']; + + LINEBREAKS = ['TERMINATOR', 'INDENT', 'OUTDENT']; + + +}); \ No newline at end of file diff --git a/lib/ace/mode/coffee/scope.js b/lib/ace/mode/coffee/scope.js new file mode 100644 index 0000000000..11c0f795d2 --- /dev/null +++ b/lib/ace/mode/coffee/scope.js @@ -0,0 +1,173 @@ +/** + * Copyright (c) 2009-2012 Jeremy Ashkenas + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +define(function(require, exports, module) { +// Generated by CoffeeScript 1.3.3 + + var Scope, extend, last, _ref; + + _ref = require('./helpers'), extend = _ref.extend, last = _ref.last; + + exports.Scope = Scope = (function() { + + Scope.root = null; + + function Scope(parent, expressions, method) { + this.parent = parent; + this.expressions = expressions; + this.method = method; + this.variables = [ + { + name: 'arguments', + type: 'arguments' + } + ]; + this.positions = {}; + if (!this.parent) { + Scope.root = this; + } + } + + Scope.prototype.add = function(name, type, immediate) { + if (this.shared && !immediate) { + return this.parent.add(name, type, immediate); + } + if (Object.prototype.hasOwnProperty.call(this.positions, name)) { + return this.variables[this.positions[name]].type = type; + } else { + return this.positions[name] = this.variables.push({ + name: name, + type: type + }) - 1; + } + }; + + Scope.prototype.namedMethod = function() { + if (this.method.name || !this.parent) { + return this.method; + } + return this.parent.namedMethod(); + }; + + Scope.prototype.find = function(name) { + if (this.check(name)) { + return true; + } + this.add(name, 'var'); + return false; + }; + + Scope.prototype.parameter = function(name) { + if (this.shared && this.parent.check(name, true)) { + return; + } + return this.add(name, 'param'); + }; + + Scope.prototype.check = function(name) { + var _ref1; + return !!(this.type(name) || ((_ref1 = this.parent) != null ? _ref1.check(name) : void 0)); + }; + + Scope.prototype.temporary = function(name, index) { + if (name.length > 1) { + return '_' + name + (index > 1 ? index - 1 : ''); + } else { + return '_' + (index + parseInt(name, 36)).toString(36).replace(/\d/g, 'a'); + } + }; + + Scope.prototype.type = function(name) { + var v, _i, _len, _ref1; + _ref1 = this.variables; + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + v = _ref1[_i]; + if (v.name === name) { + return v.type; + } + } + return null; + }; + + Scope.prototype.freeVariable = function(name, reserve) { + var index, temp; + if (reserve == null) { + reserve = true; + } + index = 0; + while (this.check((temp = this.temporary(name, index)))) { + index++; + } + if (reserve) { + this.add(temp, 'var', true); + } + return temp; + }; + + Scope.prototype.assign = function(name, value) { + this.add(name, { + value: value, + assigned: true + }, true); + return this.hasAssignments = true; + }; + + Scope.prototype.hasDeclarations = function() { + return !!this.declaredVariables().length; + }; + + Scope.prototype.declaredVariables = function() { + var realVars, tempVars, v, _i, _len, _ref1; + realVars = []; + tempVars = []; + _ref1 = this.variables; + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + v = _ref1[_i]; + if (v.type === 'var') { + (v.name.charAt(0) === '_' ? tempVars : realVars).push(v.name); + } + } + return realVars.sort().concat(tempVars.sort()); + }; + + Scope.prototype.assignedVariables = function() { + var v, _i, _len, _ref1, _results; + _ref1 = this.variables; + _results = []; + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + v = _ref1[_i]; + if (v.type.assigned) { + _results.push("" + v.name + " = " + v.type.value); + } + } + return _results; + }; + + return Scope; + + })(); + + +}); \ No newline at end of file diff --git a/lib/ace/mode/coffee_highlight_rules.js b/lib/ace/mode/coffee_highlight_rules.js new file mode 100644 index 0000000000..80fb7ffa9d --- /dev/null +++ b/lib/ace/mode/coffee_highlight_rules.js @@ -0,0 +1,328 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + + var oop = require("../lib/oop"); + var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + + oop.inherits(CoffeeHighlightRules, TextHighlightRules); + + function CoffeeHighlightRules() { + var identifier = "[$A-Za-z_\\x7f-\\uffff][$\\w\\x7f-\\uffff]*"; + var stringfill = { + token : "string", + merge : true, + regex : ".+" + }; + + var keywords = ( + "this|throw|then|try|typeof|super|switch|return|break|by|continue|" + + "catch|class|in|instanceof|is|isnt|if|else|extends|for|forown|" + + "finally|function|while|when|new|no|not|delete|debugger|do|loop|of|off|" + + "or|on|unless|until|and|yes" + ); + + var langConstant = ( + "true|false|null|undefined|NaN|Infinity" + ); + + var illegal = ( + "case|const|default|function|var|void|with|enum|export|implements|" + + "interface|let|package|private|protected|public|static|yield|" + + "__hasProp|slice|bind|indexOf" + ); + + var supportClass = ( + "Array|Boolean|Date|Function|Number|Object|RegExp|ReferenceError|String|" + + "Error|EvalError|InternalError|RangeError|ReferenceError|StopIteration|" + + "SyntaxError|TypeError|URIError|" + + "ArrayBuffer|Float32Array|Float64Array|Int16Array|Int32Array|Int8Array|" + + "Uint16Array|Uint32Array|Uint8Array|Uint8ClampedArray" + ); + + var supportFunction = ( + "Math|JSON|isNaN|isFinite|parseInt|parseFloat|encodeURI|" + + "encodeURIComponent|decodeURI|decodeURIComponent|String|" + ); + + var variableLanguage = ( + "window|arguments|prototype|document" + ); + + var keywordMapper = this.createKeywordMapper({ + "keyword": keywords, + "constant.language": langConstant, + "invalid.illegal": illegal, + "language.support.class": supportClass, + "language.support.function": supportFunction, + "variable.language": variableLanguage + }, "identifier"); + + var functionRules = { + "({args})->": { + token: ["paren.lparen", "text", "paren.lparen", "text", "variable.parameter", "text", "paren.rparen", "text", "paren.rparen", "text", "storage.type"], + regex: "(\\()(\\s*)(\\{)(\\s*)([$@A-Za-z_\\x7f-\\uffff][$@\\w\\s,\\x7f-\\uffff]*)(\\s*)(\\})(\\s*)(\\))(\\s*)([\\-=]>)" + }, + "({})->": { + token: ["paren.lparen", "text", "paren.lparen", "text", "paren.rparen", "text", "paren.rparen", "text", "storage.type"], + regex: "(\\()(\\s*)(\\{)(\\s*)(\\})(\\s*)(\\))(\\s*)([\\-=]>)" + }, + "(args)->": { + token: ["paren.lparen", "text", "variable.parameter", "text", "paren.rparen", "text", "storage.type"], + regex: "(\\()(\\s*)([$@A-Za-z_\\x7f-\\uffff][\\s\\x21-\\uffff]*)(\\s*)(\\))(\\s*)([\\-=]>)" + }, + "()->": { + token: ["paren.lparen", "text", "paren.rparen", "text", "storage.type"], + regex: "(\\()(\\s*)(\\))(\\s*)([\\-=]>)" + } + }; + + this.$rules = { + start : [ + { + token : "constant.numeric", + regex : "(?:0x[\\da-fA-F]+|(?:\\d+(?:\\.\\d+)?|\\.\\d+)(?:[eE][+-]?\\d+)?)" + }, { + token : "string", + merge : true, + regex : "'''", + next : "qdoc" + }, { + token : "string", + merge : true, + regex : '"""', + next : "qqdoc" + }, { + token : "string", + merge : true, + regex : "'", + next : "qstring" + }, { + token : "string", + merge : true, + regex : '"', + next : "qqstring" + }, { + token : "string", + merge : true, + regex : "`", + next : "js" + }, { + token : "string.regex", + merge : true, + regex : "///", + next : "heregex" + }, { + token : "string.regex", + regex : /(?:\/(?![\s=])[^[\/\n\\]*(?:(?:\\[\s\S]|\[[^\]\n\\]*(?:\\[\s\S][^\]\n\\]*)*])[^[\/\n\\]*)*\/)(?:[imgy]{0,4})(?!\w)/ + }, { + token : "comment", + merge : true, + regex : "###(?!#)", + next : "comment" + }, { + token : "comment", + regex : "#.*" + }, { + token : [ + "punctuation.operator", "identifier" + ], + regex : "(\\.)(" + illegal + ")" + }, { + token : "punctuation.operator", + regex : "\\." + }, { + //class A extends B + token : [ + "keyword", "text", "language.support.class", "text", "keyword", "text", "language.support.class" + ], + regex : "(class)(\\s+)(" + identifier + ")(\\s+)(extends)(\\s+)(" + identifier + ")" + }, { + //class A + token : [ + "keyword", "text", "language.support.class" + ], + regex : "(class)(\\s+)(" + identifier + ")" + }, { + //play = ({args}) -> + token : [ + "entity.name.function", "text", "keyword.operator", "text" + ].concat(functionRules["({args})->"].token), + regex : "(" + identifier + ")(\\s*)(=)(\\s*)" + functionRules["({args})->"].regex + }, { + //play : ({args}) -> + token : [ + "entity.name.function", "text", "punctuation.operator", "text" + ].concat(functionRules["({args})->"].token), + regex : "(" + identifier + ")(\\s*)(:)(\\s*)" + functionRules["({args})->"].regex + }, { + //play = ({}) -> + token : [ + "entity.name.function", "text", "keyword.operator", "text" + ].concat(functionRules["({})->"].token), + regex : "(" + identifier + ")(\\s*)(=)(\\s*)" + functionRules["({})->"].regex + }, { + //play : ({}) -> + token : [ + "entity.name.function", "text", "punctuation.operator", "text" + ].concat(functionRules["({})->"].token), + regex : "(" + identifier + ")(\\s*)(:)(\\s*)" + functionRules["({})->"].regex + }, { + //play = (args) -> + token : [ + "entity.name.function", "text", "keyword.operator", "text" + ].concat(functionRules["(args)->"].token), + regex : "(" + identifier + ")(\\s*)(=)(\\s*)" + functionRules["(args)->"].regex + }, { + //play : (args) -> + token : [ + "entity.name.function", "text", "punctuation.operator", "text" + ].concat(functionRules["(args)->"].token), + regex : "(" + identifier + ")(\\s*)(:)(\\s*)" + functionRules["(args)->"].regex + }, { + //play = () -> + token : [ + "entity.name.function", "text", "keyword.operator", "text" + ].concat(functionRules["()->"].token), + regex : "(" + identifier + ")(\\s*)(=)(\\s*)" + functionRules["()->"].regex + }, { + //play : () -> + token : [ + "entity.name.function", "text", "punctuation.operator", "text" + ].concat(functionRules["()->"].token), + regex : "(" + identifier + ")(\\s*)(:)(\\s*)" + functionRules["()->"].regex + }, { + //play = -> + token : [ + "entity.name.function", "text", "keyword.operator", "text", "storage.type" + ], + regex : "(" + identifier + ")(\\s*)(=)(\\s*)([\\-=]>)" + }, { + //play : -> + token : [ + "entity.name.function", "text", "punctuation.operator", "text", "storage.type" + ], + regex : "(" + identifier + ")(\\s*)(:)(\\s*)([\\-=]>)" + }, + functionRules["({args})->"], + functionRules["({})->"], + functionRules["(args)->"], + functionRules["()->"] + , { + token : "identifier", + regex : "(?:(?:\\.|::)\\s*)" + identifier + }, { + token : "variable", + regex : "@(?:" + identifier + ")?" + }, { + token: keywordMapper, + regex : identifier + }, { + token : "punctuation.operator", + regex : "\\?|\\:|\\,|\\." + }, { + token : "storage.type", + regex : "[\\-=]>" + }, { + token : "keyword.operator", + regex : "(?:[-+*/%<>&|^!?=]=|>>>=?|\\-\\-|\\+\\+|::|&&=|\\|\\|=|<<=|>>=|\\?\\.|\\.{2,3}|[!*+-=><])" + }, { + token : "paren.lparen", + regex : "[({[]" + }, { + token : "paren.rparen", + regex : "[\\]})]" + }, { + token : "text", + regex : "\\s+" + }], + + qdoc : [{ + token : "string", + regex : ".*?'''", + next : "start" + }, stringfill], + + qqdoc : [{ + token : "string", + regex : '.*?"""', + next : "start" + }, stringfill], + + qstring : [{ + token : "string", + regex : "[^\\\\']*(?:\\\\.[^\\\\']*)*'", + merge : true, + next : "start" + }, stringfill], + + qqstring : [{ + token : "string", + regex : '[^\\\\"]*(?:\\\\.[^\\\\"]*)*"', + merge : true, + next : "start" + }, stringfill], + + js : [{ + token : "string", + merge : true, + regex : "[^\\\\`]*(?:\\\\.[^\\\\`]*)*`", + next : "start" + }, stringfill], + + heregex : [{ + token : "string.regex", + regex : '.*?///[imgy]{0,4}', + next : "start" + }, { + token : "comment.regex", + regex : "\\s+(?:#.*)?" + }, { + token : "string.regex", + merge : true, + regex : "\\S+" + }], + + comment : [{ + token : "comment", + regex : '.*?###', + next : "start" + }, { + token : "comment", + merge : true, + regex : ".+" + }] + }; + } + + exports.CoffeeHighlightRules = CoffeeHighlightRules; +}); diff --git a/lib/ace/mode/coffee_highlight_rules_test.js b/lib/ace/mode/coffee_highlight_rules_test.js new file mode 100644 index 0000000000..a7cb85db87 --- /dev/null +++ b/lib/ace/mode/coffee_highlight_rules_test.js @@ -0,0 +1,266 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); +} + +define(function(require, exports, module) { +"use strict"; + +var Mode = require("./coffee").Mode; +var assert = require("../test/assertions"); + +module.exports = { + setUp : function() { + this.tokenizer = new Mode().getTokenizer(); + this.testTokens = function(tokens, correct) { + assert.equal(tokens.length, correct.length); + correct.forEach(function(type, i) { + assert.equal(tokens[i].type, type); + }); + }; + }, + + "test: tokenize keyword": function() { + var tokens = this.tokenizer.getLineTokens("for", "start").tokens; + assert.equal(tokens.length, 1); + assert.equal(tokens[0].type, "keyword"); + }, + + "test: tokenize regexp": function() { + var tokens = this.tokenizer.getLineTokens('/"[a]/', "start").tokens; + assert.equal(tokens.length, 1); + assert.equal(tokens[0].type, "string.regex"); + }, + + "test: tokenize function: 'foo = ({args}) ->'": function() { + var tokens = this.tokenizer.getLineTokens("foo = ({args}) ->", "start").tokens; + var correct = [ + "entity.name.function", "text", "keyword.operator", "text", + "paren.lparen", "paren.lparen", "variable.parameter", "paren.rparen", "paren.rparen", "text", "storage.type" + ]; + this.testTokens(tokens, correct); + + tokens = this.tokenizer.getLineTokens("foo = ({a1, a2}) ->", "start").tokens; + this.testTokens(tokens, correct); + + tokens = this.tokenizer.getLineTokens("foo = ({@a1, a2}) ->", "start").tokens; + this.testTokens(tokens, correct); + }, + + "test: tokenize function: 'foo : ({args}) ->'": function() { + var tokens = this.tokenizer.getLineTokens("foo : ({args}) ->", "start").tokens; + var correct = [ + "entity.name.function", "text", "punctuation.operator", "text", + "paren.lparen", "paren.lparen", "variable.parameter", "paren.rparen", "paren.rparen", "text", "storage.type" + ]; + this.testTokens(tokens, correct); + }, + + "test: tokenize function: invalid case: 'foo = ({args}) ->'": function() { + var tokens = this.tokenizer.getLineTokens("foo = ({0abc}) ->", "start").tokens; + assert.notEqual(tokens[0].type, "entity.name.function"); + + tokens = this.tokenizer.getLineTokens("foo = ({/abc}) ->", "start").tokens; + assert.notEqual(tokens[0].type, "entity.name.function"); + + tokens = this.tokenizer.getLineTokens("foo = ({abc/}) ->", "start").tokens; + assert.notEqual(tokens[0].type, "entity.name.function"); + + tokens = this.tokenizer.getLineTokens("foo = ({#abc}) ->", "start").tokens; + assert.notEqual(tokens[0].type, "entity.name.function"); + + tokens = this.tokenizer.getLineTokens("foo = ({abc#}) ->", "start").tokens; + assert.notEqual(tokens[0].type, "entity.name.function"); + + tokens = this.tokenizer.getLineTokens("foo = ({)abc}) ->", "start").tokens; + assert.notEqual(tokens[0].type, "entity.name.function"); + + tokens = this.tokenizer.getLineTokens("foo = ({abc)}) ->", "start").tokens; + assert.notEqual(tokens[0].type, "entity.name.function"); + + tokens = this.tokenizer.getLineTokens("foo = ({a{bc}) ->", "start").tokens; + assert.notEqual(tokens[0].type, "entity.name.function"); + }, + + "test: tokenize function: 'foo = ({}) ->'": function() { + var tokens = this.tokenizer.getLineTokens("foo = ({}) ->", "start").tokens; + var correct = [ + "entity.name.function", "text", "keyword.operator", "text", + "paren.lparen", "paren.lparen", "paren.rparen", "paren.rparen", "text", "storage.type" + ]; + this.testTokens(tokens, correct); + + tokens = this.tokenizer.getLineTokens("foo = ({ }) ->", "start").tokens; + correct = [ + "entity.name.function", "text", "keyword.operator", "text", + "paren.lparen", "paren.lparen", "text", "paren.rparen", "paren.rparen", "text", "storage.type" + ]; + assert.equal(tokens.length, 11); + this.testTokens(tokens, correct); + }, + + "test: tokenize function: 'foo : ({}) ->'": function() { + var tokens = this.tokenizer.getLineTokens("foo : ({}) ->", "start").tokens; + var correct = [ + "entity.name.function", "text", "punctuation.operator", "text", + "paren.lparen", "paren.lparen", "paren.rparen", "paren.rparen", "text", "storage.type" + ]; + this.testTokens(tokens, correct); + }, + + "test: tokenize function: 'foo = (args) ->'": function() { + var tokens = this.tokenizer.getLineTokens("foo = (args) ->", "start").tokens; + var correct = [ + "entity.name.function", "text", "keyword.operator", "text", + "paren.lparen", "variable.parameter", "paren.rparen", "text", "storage.type" + ]; + this.testTokens(tokens, correct); + + tokens = this.tokenizer.getLineTokens("foo = (arg1, arg2) ->", "start").tokens; + this.testTokens(tokens, correct); + + tokens = this.tokenizer.getLineTokens("foo = (arg1 = 1, arg2 = 'name') ->", "start").tokens; + this.testTokens(tokens, correct); + + tokens = this.tokenizer.getLineTokens("foo = (@arg1 = /abc/, arg2 = 'name') ->", "start").tokens; + this.testTokens(tokens, correct); + }, + + "test: tokenize function: invalid case: 'foo=(args) ->'": function() { + var tokens = this.tokenizer.getLineTokens("foo=(/args) ->", "start").tokens; + assert.notEqual(tokens[0].type, "entity.name.function"); + }, + + "test: tokenize function: 'foo = () ->'": function() { + var tokens = this.tokenizer.getLineTokens("foo = () ->", "start").tokens; + var correct = [ + "entity.name.function", "text", "keyword.operator", "text", + "paren.lparen", "paren.rparen", "text", "storage.type" + ]; + this.testTokens(tokens, correct); + + tokens = this.tokenizer.getLineTokens("foo = ( ) ->", "start").tokens; + correct = [ + "entity.name.function", "text", "keyword.operator", "text", + "paren.lparen", "text", "paren.rparen", "text", "storage.type" + ]; + this.testTokens(tokens, correct); + }, + + "test: tokenize function: 'foo : () ->'": function() { + var tokens = this.tokenizer.getLineTokens("foo : () ->", "start").tokens; + var correct = [ + "entity.name.function", "text", "punctuation.operator", "text", + "paren.lparen", "paren.rparen", "text", "storage.type" + ]; + this.testTokens(tokens, correct); + + tokens = this.tokenizer.getLineTokens("foo : ( ) ->", "start").tokens; + var correct = [ + "entity.name.function", "text", "punctuation.operator", "text", + "paren.lparen", "text", "paren.rparen", "text", "storage.type" + ]; + this.testTokens(tokens, correct); + }, + + "test: tokenize function: 'window.foo = (args) ->'": function() { + var tokens = this.tokenizer.getLineTokens("window.foo = (args) ->", "start").tokens; + var correct = [ + "variable.language", "punctuation.operator", "entity.name.function", "text", "keyword.operator", "text", + "paren.lparen", "variable.parameter", "paren.rparen", "text", "storage.type" + ]; + this.testTokens(tokens, correct); + }, + + "test: tokenize function: 'foo = ->'": function() { + var tokens = this.tokenizer.getLineTokens("foo = ->", "start").tokens; + var correct = [ + "entity.name.function", "text", "keyword.operator", "text", "storage.type" + ]; + this.testTokens(tokens, correct); + }, + + "test: tokenize function: 'foo : ->'": function() { + var tokens = this.tokenizer.getLineTokens("foo : ->", "start").tokens; + var correct = [ + "entity.name.function", "text", "punctuation.operator", "text", "storage.type" + ]; + this.testTokens(tokens, correct); + }, + + "test: tokenize callback function: 'foo bar: 1, (args) ->'": function() { + var tokens = this.tokenizer.getLineTokens("foo bar: 1, (args) ->", "start").tokens; + var correct = [ + "identifier", "text", "identifier", "punctuation.operator", "text", "constant.numeric", "punctuation.operator", "text", + "paren.lparen", "variable.parameter", "paren.rparen", "text", "storage.type" + ]; + this.testTokens(tokens, correct); + }, + + "test: tokenize class: 'class Foo'": function() { + var tokens = this.tokenizer.getLineTokens("class Foo", "start").tokens; + var correct = [ + "keyword", "text", "language.support.class" + ]; + this.testTokens(tokens, correct); + }, + + "test: tokenize class 'class Foo extends Bar'": function() { + var tokens = this.tokenizer.getLineTokens("class Foo extends Bar", "start").tokens; + var correct = [ + "keyword", "text", "language.support.class", "text", "keyword", "text", "language.support.class" + ]; + this.testTokens(tokens, correct); + }, + + "test: tokenize illegal name property: 'foo.static.function'": function() { + var tokens = this.tokenizer.getLineTokens("foo.static.function", "start").tokens; + var correct = [ + "identifier", "punctuation.operator", "identifier", "punctuation.operator", "identifier" + ]; + this.testTokens(tokens, correct); + }, + + // TODO: disable. not yet implemented + "!test tokenize string with interpolation": function() { + var tokens = this.tokenizer.getLineTokens('"#{ 22 / 7 } is a decent approximation of π"', "start").tokens; + console.log(tokens); + assert.equal(tokens.length, 12); + //assert.equal(tokens[0].type, "keyword"); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/lib/ace/mode/coffee_worker.js b/lib/ace/mode/coffee_worker.js new file mode 100644 index 0000000000..e656cae916 --- /dev/null +++ b/lib/ace/mode/coffee_worker.js @@ -0,0 +1,85 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var Mirror = require("../worker/mirror").Mirror; +var coffee = require("../mode/coffee/coffee-script"); + +window.addEventListener = function() {}; + + +var Worker = exports.Worker = function(sender) { + Mirror.call(this, sender); + this.setTimeout(200); +}; + +oop.inherits(Worker, Mirror); + +(function() { + + this.onUpdate = function() { + var value = this.doc.getValue(); + + try { + coffee.parse(value); + } catch(e) { + var m = e.message.match(/Parse error on line (\d+): (.*)/); + if (m) { + this.sender.emit("error", { + row: parseInt(m[1], 10) - 1, + column: null, + text: m[2], + type: "error" + }); + return; + } + + if (e instanceof SyntaxError) { + var m = e.message.match(/ on line (\d+)/); + if (m) { + this.sender.emit("error", { + row: parseInt(m[1], 10) - 1, + column: null, + text: e.message.replace(m[0], ""), + type: "error" + }); + } + } + return; + } + this.sender.emit("ok"); + }; + +}).call(Worker.prototype); + +}); diff --git a/lib/ace/mode/coldfusion.js b/lib/ace/mode/coldfusion.js new file mode 100644 index 0000000000..fc62a89eef --- /dev/null +++ b/lib/ace/mode/coldfusion.js @@ -0,0 +1,64 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var XmlMode = require("./xml").Mode; +var JavaScriptMode = require("./javascript").Mode; +var CssMode = require("./css").Mode; +var Tokenizer = require("../tokenizer").Tokenizer; +var ColdfusionHighlightRules = require("./coldfusion_highlight_rules").ColdfusionHighlightRules; + +var Mode = function() { + XmlMode.call(this); + + var highlighter = new ColdfusionHighlightRules(); + this.$tokenizer = new Tokenizer(highlighter.getRules()); + + this.$embeds = highlighter.getEmbeds(); + this.createModeDelegates({ + "js-": JavaScriptMode, + "css-": CssMode + }); +}; +oop.inherits(Mode, XmlMode); + +(function() { + + this.getNextLineIndent = function(state, line, tab) { + return this.$getIndent(line); + }; + +}).call(Mode.prototype); + +exports.Mode = Mode; +}); diff --git a/lib/ace/mode/coldfusion_highlight_rules.js b/lib/ace/mode/coldfusion_highlight_rules.js new file mode 100644 index 0000000000..7f4a1e3f17 --- /dev/null +++ b/lib/ace/mode/coldfusion_highlight_rules.js @@ -0,0 +1,128 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var CssHighlightRules = require("./css_highlight_rules").CssHighlightRules; +var JavaScriptHighlightRules = require("./javascript_highlight_rules").JavaScriptHighlightRules; +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; +var xml_util = require("./xml_util"); + +var ColdfusionHighlightRules = function() { + + // regexp must not have capturing parentheses + // regexps are ordered -> the first match is used + + this.$rules = { + start : [ { + token : "text", + merge : true, + regex : "<\\!\\[CDATA\\[", + next : "cdata" + }, { + token : "xml-pe", + regex : "<\\?.*?\\?>" + }, { + token : "comment", + merge : true, + regex : "<\\!--", + next : "comment" + }, { + token : "meta.tag", + regex : "<(?=script)", + next : "script" + }, { + token : "meta.tag", + regex : "<(?=style)", + next : "style" + }, { + token : "meta.tag", // opening tag + regex : "<\\/?", + next : "tag" + }, { + token : "text", + regex : "\\s+" + }, { + token : "text", + regex : "[^<]+" + } ], + + cdata : [ { + token : "text", + regex : "\\]\\]>", + next : "start" + }, { + token : "text", + merge : true, + regex : "\\s+" + }, { + token : "text", + merge : true, + regex : ".+" + } ], + + comment : [ { + token : "comment", + regex : ".*?-->", + next : "start" + }, { + token : "comment", + merge : true, + regex : ".+" + } ] + }; + + xml_util.tag(this.$rules, "tag", "start"); + xml_util.tag(this.$rules, "style", "css-start"); + xml_util.tag(this.$rules, "script", "js-start"); + + this.embedRules(JavaScriptHighlightRules, "js-", [{ + token: "comment", + regex: "\\/\\/.*(?=<\\/script>)", + next: "tag" + }, { + token: "meta.tag", + regex: "<\\/(?=script)", + next: "tag" + }]); + + this.embedRules(CssHighlightRules, "css-", [{ + token: "meta.tag", + regex: "<\\/(?=style)", + next: "tag" + }]); +}; + +oop.inherits(ColdfusionHighlightRules, TextHighlightRules); + +exports.ColdfusionHighlightRules = ColdfusionHighlightRules; +}); diff --git a/lib/ace/mode/coldfusion_test.js b/lib/ace/mode/coldfusion_test.js new file mode 100644 index 0000000000..97bfb83e99 --- /dev/null +++ b/lib/ace/mode/coldfusion_test.js @@ -0,0 +1,67 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); +} + +define(function(require, exports, module) { +"use strict"; + +var EditSession = require("../edit_session").EditSession; +var Range = require("../range").Range; +var ColdfusionMode = require("./coldfusion").Mode; +var assert = require("../test/assertions"); + +module.exports = { + setUp : function() { + this.mode = new ColdfusionMode(); + }, + + "test: toggle comment lines should not do anything" : function() { + var session = new EditSession([" abc", "cde", "fg"]); + + var range = new Range(0, 3, 1, 1); + var comment = this.mode.toggleCommentLines("start", session, 0, 1); + assert.equal([" abc", "cde", "fg"].join("\n"), session.toString()); + }, + + "test: next line indent should be the same as the current line indent" : function() { + assert.equal(" ", this.mode.getNextLineIndent("start", " abc")); + assert.equal("", this.mode.getNextLineIndent("start", "abc")); + assert.equal("\t", this.mode.getNextLineIndent("start", "\tabc")); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec() +} diff --git a/lib/ace/mode/csharp.js b/lib/ace/mode/csharp.js new file mode 100644 index 0000000000..25586b8031 --- /dev/null +++ b/lib/ace/mode/csharp.js @@ -0,0 +1,58 @@ +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var Tokenizer = require("../tokenizer").Tokenizer; +var CSharpHighlightRules = require("./csharp_highlight_rules").CSharpHighlightRules; +var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; +var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour; +var CStyleFoldMode = require("./folding/cstyle").FoldMode; + +var Mode = function() { + this.$tokenizer = new Tokenizer(new CSharpHighlightRules().getRules()); + this.$outdent = new MatchingBraceOutdent(); + this.$behaviour = new CstyleBehaviour(); + this.foldingRules = new CStyleFoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + + this.getNextLineIndent = function(state, line, tab) { + var indent = this.$getIndent(line); + + var tokenizedLine = this.$tokenizer.getLineTokens(line, state); + var tokens = tokenizedLine.tokens; + + if (tokens.length && tokens[tokens.length-1].type == "comment") { + return indent; + } + + if (state == "start") { + var match = line.match(/^.*[\{\(\[]\s*$/); + if (match) { + indent += tab; + } + } + + return indent; + }; + + this.checkOutdent = function(state, line, input) { + return this.$outdent.checkOutdent(line, input); + }; + + this.autoOutdent = function(state, doc, row) { + this.$outdent.autoOutdent(doc, row); + }; + + + this.createWorker = function(session) { + return null; + }; + +}).call(Mode.prototype); + +exports.Mode = Mode; +}); diff --git a/lib/ace/mode/csharp_highlight_rules.js b/lib/ace/mode/csharp_highlight_rules.js new file mode 100644 index 0000000000..22bbd82c54 --- /dev/null +++ b/lib/ace/mode/csharp_highlight_rules.js @@ -0,0 +1,90 @@ +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var DocCommentHighlightRules = require("./doc_comment_highlight_rules").DocCommentHighlightRules; +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var CSharpHighlightRules = function() { + var keywordMapper = this.createKeywordMapper({ + "variable.language": "this", + "keyword": "abstract|event|new|struct|as|explicit|null|switch|base|extern|object|this|bool|false|operator|throw|break|finally|out|true|byte|fixed|override|try|case|float|params|typeof|catch|for|private|uint|char|foreach|protected|ulong|checked|goto|public|unchecked|class|if|readonly|unsafe|const|implicit|ref|ushort|continue|in|return|using|decimal|int|sbyte|virtual|default|interface|sealed|volatile|delegate|internal|short|void|do|is|sizeof|while|double|lock|stackalloc|else|long|static|enum|namespace|string|var|dynamic", + "constant.language": "null|true|false" + }, "identifier"); + + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + + this.$rules = { + "start" : [ + { + token : "comment", + regex : "\\/\\/.*$" + }, + DocCommentHighlightRules.getStartRule("doc-start"), + { + token : "comment", // multi line comment + regex : "\\/\\*", + merge : true, + next : "comment" + }, { + token : "string.regexp", + regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)" + }, { + token : "string", // single line + regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]' + }, { + token : "string", // single line + regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']" + }, { + token : "constant.numeric", // hex + regex : "0[xX][0-9a-fA-F]+\\b" + }, { + token : "constant.numeric", // float + regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b" + }, { + token : "constant.language.boolean", + regex : "(?:true|false)\\b" + }, { + token : keywordMapper, + // TODO: Unicode escape sequences + // TODO: Unicode identifiers + regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" + }, { + token : "keyword.operator", + regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)" + }, { + token : "punctuation.operator", + regex : "\\?|\\:|\\,|\\;|\\." + }, { + token : "paren.lparen", + regex : "[[({]" + }, { + token : "paren.rparen", + regex : "[\\])}]" + }, { + token : "text", + regex : "\\s+" + } + ], + "comment" : [ + { + token : "comment", // closing comment + regex : ".*?\\*\\/", + next : "start" + }, { + token : "comment", // comment spanning whole line + merge : true, + regex : ".+" + } + ] + }; + + this.embedRules(DocCommentHighlightRules, "doc-", + [ DocCommentHighlightRules.getEndRule("start") ]); +}; + +oop.inherits(CSharpHighlightRules, TextHighlightRules); + +exports.CSharpHighlightRules = CSharpHighlightRules; +}); diff --git a/lib/ace/mode/css.js b/lib/ace/mode/css.js new file mode 100644 index 0000000000..447a81815e --- /dev/null +++ b/lib/ace/mode/css.js @@ -0,0 +1,97 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var Tokenizer = require("../tokenizer").Tokenizer; +var CssHighlightRules = require("./css_highlight_rules").CssHighlightRules; +var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; +var WorkerClient = require("../worker/worker_client").WorkerClient; +var CStyleFoldMode = require("./folding/cstyle").FoldMode; + +var Mode = function() { + this.$tokenizer = new Tokenizer(new CssHighlightRules().getRules(), "i"); + this.$outdent = new MatchingBraceOutdent(); + this.foldingRules = new CStyleFoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + + this.foldingRules = "cStyle"; + + this.getNextLineIndent = function(state, line, tab) { + var indent = this.$getIndent(line); + + // ignore braces in comments + var tokens = this.$tokenizer.getLineTokens(line, state).tokens; + if (tokens.length && tokens[tokens.length-1].type == "comment") { + return indent; + } + + var match = line.match(/^.*\{\s*$/); + if (match) { + indent += tab; + } + + return indent; + }; + + this.checkOutdent = function(state, line, input) { + return this.$outdent.checkOutdent(line, input); + }; + + this.autoOutdent = function(state, doc, row) { + this.$outdent.autoOutdent(doc, row); + }; + + this.createWorker = function(session) { + var worker = new WorkerClient(["ace"], "ace/mode/css_worker", "Worker"); + worker.attachToDocument(session.getDocument()); + + worker.on("csslint", function(e) { + session.setAnnotations(e.data); + }); + + worker.on("terminate", function() { + session.clearAnnotations(); + }); + + return worker; + }; + +}).call(Mode.prototype); + +exports.Mode = Mode; + +}); diff --git a/lib/ace/mode/css/csslint.js b/lib/ace/mode/css/csslint.js new file mode 100644 index 0000000000..4f38daef71 --- /dev/null +++ b/lib/ace/mode/css/csslint.js @@ -0,0 +1,8519 @@ +define(function(require, exports, module) { +/*! +CSSLint +Copyright (c) 2011 Nicole Sullivan and Nicholas C. Zakas. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ +/* Build time: 12-September-2012 01:46:26 */ + +/*! +Parser-Lib +Copyright (c) 2009-2011 Nicholas C. Zakas. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ +/* Version v0.1.9, Build time: 23-July-2012 10:52:31 */ +var parserlib = {}; +(function(){ + + +/** + * A generic base to inherit from for any object + * that needs event handling. + * @class EventTarget + * @constructor + */ +function EventTarget(){ + + /** + * The array of listeners for various events. + * @type Object + * @property _listeners + * @private + */ + this._listeners = {}; +} + +EventTarget.prototype = { + + //restore constructor + constructor: EventTarget, + + /** + * Adds a listener for a given event type. + * @param {String} type The type of event to add a listener for. + * @param {Function} listener The function to call when the event occurs. + * @return {void} + * @method addListener + */ + addListener: function(type, listener){ + if (!this._listeners[type]){ + this._listeners[type] = []; + } + + this._listeners[type].push(listener); + }, + + /** + * Fires an event based on the passed-in object. + * @param {Object|String} event An object with at least a 'type' attribute + * or a string indicating the event name. + * @return {void} + * @method fire + */ + fire: function(event){ + if (typeof event == "string"){ + event = { type: event }; + } + if (typeof event.target != "undefined"){ + event.target = this; + } + + if (typeof event.type == "undefined"){ + throw new Error("Event object missing 'type' property."); + } + + if (this._listeners[event.type]){ + + //create a copy of the array and use that so listeners can't chane + var listeners = this._listeners[event.type].concat(); + for (var i=0, len=listeners.length; i < len; i++){ + listeners[i].call(this, event); + } + } + }, + + /** + * Removes a listener for a given event type. + * @param {String} type The type of event to remove a listener from. + * @param {Function} listener The function to remove from the event. + * @return {void} + * @method removeListener + */ + removeListener: function(type, listener){ + if (this._listeners[type]){ + var listeners = this._listeners[type]; + for (var i=0, len=listeners.length; i < len; i++){ + if (listeners[i] === listener){ + listeners.splice(i, 1); + break; + } + } + + + } + } +}; +/** + * Convenient way to read through strings. + * @namespace parserlib.util + * @class StringReader + * @constructor + * @param {String} text The text to read. + */ +function StringReader(text){ + + /** + * The input text with line endings normalized. + * @property _input + * @type String + * @private + */ + this._input = text.replace(/\n\r?/g, "\n"); + + + /** + * The row for the character to be read next. + * @property _line + * @type int + * @private + */ + this._line = 1; + + + /** + * The column for the character to be read next. + * @property _col + * @type int + * @private + */ + this._col = 1; + + /** + * The index of the character in the input to be read next. + * @property _cursor + * @type int + * @private + */ + this._cursor = 0; +} + +StringReader.prototype = { + + //restore constructor + constructor: StringReader, + + //------------------------------------------------------------------------- + // Position info + //------------------------------------------------------------------------- + + /** + * Returns the column of the character to be read next. + * @return {int} The column of the character to be read next. + * @method getCol + */ + getCol: function(){ + return this._col; + }, + + /** + * Returns the row of the character to be read next. + * @return {int} The row of the character to be read next. + * @method getLine + */ + getLine: function(){ + return this._line ; + }, + + /** + * Determines if you're at the end of the input. + * @return {Boolean} True if there's no more input, false otherwise. + * @method eof + */ + eof: function(){ + return (this._cursor == this._input.length); + }, + + //------------------------------------------------------------------------- + // Basic reading + //------------------------------------------------------------------------- + + /** + * Reads the next character without advancing the cursor. + * @param {int} count How many characters to look ahead (default is 1). + * @return {String} The next character or null if there is no next character. + * @method peek + */ + peek: function(count){ + var c = null; + count = (typeof count == "undefined" ? 1 : count); + + //if we're not at the end of the input... + if (this._cursor < this._input.length){ + + //get character and increment cursor and column + c = this._input.charAt(this._cursor + count - 1); + } + + return c; + }, + + /** + * Reads the next character from the input and adjusts the row and column + * accordingly. + * @return {String} The next character or null if there is no next character. + * @method read + */ + read: function(){ + var c = null; + + //if we're not at the end of the input... + if (this._cursor < this._input.length){ + + //if the last character was a newline, increment row count + //and reset column count + if (this._input.charAt(this._cursor) == "\n"){ + this._line++; + this._col=1; + } else { + this._col++; + } + + //get character and increment cursor and column + c = this._input.charAt(this._cursor++); + } + + return c; + }, + + //------------------------------------------------------------------------- + // Misc + //------------------------------------------------------------------------- + + /** + * Saves the current location so it can be returned to later. + * @method mark + * @return {void} + */ + mark: function(){ + this._bookmark = { + cursor: this._cursor, + line: this._line, + col: this._col + }; + }, + + reset: function(){ + if (this._bookmark){ + this._cursor = this._bookmark.cursor; + this._line = this._bookmark.line; + this._col = this._bookmark.col; + delete this._bookmark; + } + }, + + //------------------------------------------------------------------------- + // Advanced reading + //------------------------------------------------------------------------- + + /** + * Reads up to and including the given string. Throws an error if that + * string is not found. + * @param {String} pattern The string to read. + * @return {String} The string when it is found. + * @throws Error when the string pattern is not found. + * @method readTo + */ + readTo: function(pattern){ + + var buffer = "", + c; + + /* + * First, buffer must be the same length as the pattern. + * Then, buffer must end with the pattern or else reach the + * end of the input. + */ + while (buffer.length < pattern.length || buffer.lastIndexOf(pattern) != buffer.length - pattern.length){ + c = this.read(); + if (c){ + buffer += c; + } else { + throw new Error("Expected \"" + pattern + "\" at line " + this._line + ", col " + this._col + "."); + } + } + + return buffer; + + }, + + /** + * Reads characters while each character causes the given + * filter function to return true. The function is passed + * in each character and either returns true to continue + * reading or false to stop. + * @param {Function} filter The function to read on each character. + * @return {String} The string made up of all characters that passed the + * filter check. + * @method readWhile + */ + readWhile: function(filter){ + + var buffer = "", + c = this.read(); + + while(c !== null && filter(c)){ + buffer += c; + c = this.read(); + } + + return buffer; + + }, + + /** + * Reads characters that match either text or a regular expression and + * returns those characters. If a match is found, the row and column + * are adjusted; if no match is found, the reader's state is unchanged. + * reading or false to stop. + * @param {String|RegExp} matchter If a string, then the literal string + * value is searched for. If a regular expression, then any string + * matching the pattern is search for. + * @return {String} The string made up of all characters that matched or + * null if there was no match. + * @method readMatch + */ + readMatch: function(matcher){ + + var source = this._input.substring(this._cursor), + value = null; + + //if it's a string, just do a straight match + if (typeof matcher == "string"){ + if (source.indexOf(matcher) === 0){ + value = this.readCount(matcher.length); + } + } else if (matcher instanceof RegExp){ + if (matcher.test(source)){ + value = this.readCount(RegExp.lastMatch.length); + } + } + + return value; + }, + + + /** + * Reads a given number of characters. If the end of the input is reached, + * it reads only the remaining characters and does not throw an error. + * @param {int} count The number of characters to read. + * @return {String} The string made up the read characters. + * @method readCount + */ + readCount: function(count){ + var buffer = ""; + + while(count--){ + buffer += this.read(); + } + + return buffer; + } + +}; +/** + * Type to use when a syntax error occurs. + * @class SyntaxError + * @namespace parserlib.util + * @constructor + * @param {String} message The error message. + * @param {int} line The line at which the error occurred. + * @param {int} col The column at which the error occurred. + */ +function SyntaxError(message, line, col){ + + /** + * The column at which the error occurred. + * @type int + * @property col + */ + this.col = col; + + /** + * The line at which the error occurred. + * @type int + * @property line + */ + this.line = line; + + /** + * The text representation of the unit. + * @type String + * @property text + */ + this.message = message; + +} + +//inherit from Error +SyntaxError.prototype = new Error(); +/** + * Base type to represent a single syntactic unit. + * @class SyntaxUnit + * @namespace parserlib.util + * @constructor + * @param {String} text The text of the unit. + * @param {int} line The line of text on which the unit resides. + * @param {int} col The column of text on which the unit resides. + */ +function SyntaxUnit(text, line, col, type){ + + + /** + * The column of text on which the unit resides. + * @type int + * @property col + */ + this.col = col; + + /** + * The line of text on which the unit resides. + * @type int + * @property line + */ + this.line = line; + + /** + * The text representation of the unit. + * @type String + * @property text + */ + this.text = text; + + /** + * The type of syntax unit. + * @type int + * @property type + */ + this.type = type; +} + +/** + * Create a new syntax unit based solely on the given token. + * Convenience method for creating a new syntax unit when + * it represents a single token instead of multiple. + * @param {Object} token The token object to represent. + * @return {parserlib.util.SyntaxUnit} The object representing the token. + * @static + * @method fromToken + */ +SyntaxUnit.fromToken = function(token){ + return new SyntaxUnit(token.value, token.startLine, token.startCol); +}; + +SyntaxUnit.prototype = { + + //restore constructor + constructor: SyntaxUnit, + + /** + * Returns the text representation of the unit. + * @return {String} The text representation of the unit. + * @method valueOf + */ + valueOf: function(){ + return this.toString(); + }, + + /** + * Returns the text representation of the unit. + * @return {String} The text representation of the unit. + * @method toString + */ + toString: function(){ + return this.text; + } + +}; +/*global StringReader, SyntaxError*/ + +/** + * Generic TokenStream providing base functionality. + * @class TokenStreamBase + * @namespace parserlib.util + * @constructor + * @param {String|StringReader} input The text to tokenize or a reader from + * which to read the input. + */ +function TokenStreamBase(input, tokenData){ + + /** + * The string reader for easy access to the text. + * @type StringReader + * @property _reader + * @private + */ + this._reader = input ? new StringReader(input.toString()) : null; + + /** + * Token object for the last consumed token. + * @type Token + * @property _token + * @private + */ + this._token = null; + + /** + * The array of token information. + * @type Array + * @property _tokenData + * @private + */ + this._tokenData = tokenData; + + /** + * Lookahead token buffer. + * @type Array + * @property _lt + * @private + */ + this._lt = []; + + /** + * Lookahead token buffer index. + * @type int + * @property _ltIndex + * @private + */ + this._ltIndex = 0; + + this._ltIndexCache = []; +} + +/** + * Accepts an array of token information and outputs + * an array of token data containing key-value mappings + * and matching functions that the TokenStream needs. + * @param {Array} tokens An array of token descriptors. + * @return {Array} An array of processed token data. + * @method createTokenData + * @static + */ +TokenStreamBase.createTokenData = function(tokens){ + + var nameMap = [], + typeMap = {}, + tokenData = tokens.concat([]), + i = 0, + len = tokenData.length+1; + + tokenData.UNKNOWN = -1; + tokenData.unshift({name:"EOF"}); + + for (; i < len; i++){ + nameMap.push(tokenData[i].name); + tokenData[tokenData[i].name] = i; + if (tokenData[i].text){ + typeMap[tokenData[i].text] = i; + } + } + + tokenData.name = function(tt){ + return nameMap[tt]; + }; + + tokenData.type = function(c){ + return typeMap[c]; + }; + + return tokenData; +}; + +TokenStreamBase.prototype = { + + //restore constructor + constructor: TokenStreamBase, + + //------------------------------------------------------------------------- + // Matching methods + //------------------------------------------------------------------------- + + /** + * Determines if the next token matches the given token type. + * If so, that token is consumed; if not, the token is placed + * back onto the token stream. You can pass in any number of + * token types and this will return true if any of the token + * types is found. + * @param {int|int[]} tokenTypes Either a single token type or an array of + * token types that the next token might be. If an array is passed, + * it's assumed that the token can be any of these. + * @param {variant} channel (Optional) The channel to read from. If not + * provided, reads from the default (unnamed) channel. + * @return {Boolean} True if the token type matches, false if not. + * @method match + */ + match: function(tokenTypes, channel){ + + //always convert to an array, makes things easier + if (!(tokenTypes instanceof Array)){ + tokenTypes = [tokenTypes]; + } + + var tt = this.get(channel), + i = 0, + len = tokenTypes.length; + + while(i < len){ + if (tt == tokenTypes[i++]){ + return true; + } + } + + //no match found, put the token back + this.unget(); + return false; + }, + + /** + * Determines if the next token matches the given token type. + * If so, that token is consumed; if not, an error is thrown. + * @param {int|int[]} tokenTypes Either a single token type or an array of + * token types that the next token should be. If an array is passed, + * it's assumed that the token must be one of these. + * @param {variant} channel (Optional) The channel to read from. If not + * provided, reads from the default (unnamed) channel. + * @return {void} + * @method mustMatch + */ + mustMatch: function(tokenTypes, channel){ + + var token; + + //always convert to an array, makes things easier + if (!(tokenTypes instanceof Array)){ + tokenTypes = [tokenTypes]; + } + + if (!this.match.apply(this, arguments)){ + token = this.LT(1); + throw new SyntaxError("Expected " + this._tokenData[tokenTypes[0]].name + + " at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); + } + }, + + //------------------------------------------------------------------------- + // Consuming methods + //------------------------------------------------------------------------- + + /** + * Keeps reading from the token stream until either one of the specified + * token types is found or until the end of the input is reached. + * @param {int|int[]} tokenTypes Either a single token type or an array of + * token types that the next token should be. If an array is passed, + * it's assumed that the token must be one of these. + * @param {variant} channel (Optional) The channel to read from. If not + * provided, reads from the default (unnamed) channel. + * @return {void} + * @method advance + */ + advance: function(tokenTypes, channel){ + + while(this.LA(0) !== 0 && !this.match(tokenTypes, channel)){ + this.get(); + } + + return this.LA(0); + }, + + /** + * Consumes the next token from the token stream. + * @return {int} The token type of the token that was just consumed. + * @method get + */ + get: function(channel){ + + var tokenInfo = this._tokenData, + reader = this._reader, + value, + i =0, + len = tokenInfo.length, + found = false, + token, + info; + + //check the lookahead buffer first + if (this._lt.length && this._ltIndex >= 0 && this._ltIndex < this._lt.length){ + + i++; + this._token = this._lt[this._ltIndex++]; + info = tokenInfo[this._token.type]; + + //obey channels logic + while((info.channel !== undefined && channel !== info.channel) && + this._ltIndex < this._lt.length){ + this._token = this._lt[this._ltIndex++]; + info = tokenInfo[this._token.type]; + i++; + } + + //here be dragons + if ((info.channel === undefined || channel === info.channel) && + this._ltIndex <= this._lt.length){ + this._ltIndexCache.push(i); + return this._token.type; + } + } + + //call token retriever method + token = this._getToken(); + + //if it should be hidden, don't save a token + if (token.type > -1 && !tokenInfo[token.type].hide){ + + //apply token channel + token.channel = tokenInfo[token.type].channel; + + //save for later + this._token = token; + this._lt.push(token); + + //save space that will be moved (must be done before array is truncated) + this._ltIndexCache.push(this._lt.length - this._ltIndex + i); + + //keep the buffer under 5 items + if (this._lt.length > 5){ + this._lt.shift(); + } + + //also keep the shift buffer under 5 items + if (this._ltIndexCache.length > 5){ + this._ltIndexCache.shift(); + } + + //update lookahead index + this._ltIndex = this._lt.length; + } + + /* + * Skip to the next token if: + * 1. The token type is marked as hidden. + * 2. The token type has a channel specified and it isn't the current channel. + */ + info = tokenInfo[token.type]; + if (info && + (info.hide || + (info.channel !== undefined && channel !== info.channel))){ + return this.get(channel); + } else { + //return just the type + return token.type; + } + }, + + /** + * Looks ahead a certain number of tokens and returns the token type at + * that position. This will throw an error if you lookahead past the + * end of input, past the size of the lookahead buffer, or back past + * the first token in the lookahead buffer. + * @param {int} The index of the token type to retrieve. 0 for the + * current token, 1 for the next, -1 for the previous, etc. + * @return {int} The token type of the token in the given position. + * @method LA + */ + LA: function(index){ + var total = index, + tt; + if (index > 0){ + //TODO: Store 5 somewhere + if (index > 5){ + throw new Error("Too much lookahead."); + } + + //get all those tokens + while(total){ + tt = this.get(); + total--; + } + + //unget all those tokens + while(total < index){ + this.unget(); + total++; + } + } else if (index < 0){ + + if(this._lt[this._ltIndex+index]){ + tt = this._lt[this._ltIndex+index].type; + } else { + throw new Error("Too much lookbehind."); + } + + } else { + tt = this._token.type; + } + + return tt; + + }, + + /** + * Looks ahead a certain number of tokens and returns the token at + * that position. This will throw an error if you lookahead past the + * end of input, past the size of the lookahead buffer, or back past + * the first token in the lookahead buffer. + * @param {int} The index of the token type to retrieve. 0 for the + * current token, 1 for the next, -1 for the previous, etc. + * @return {Object} The token of the token in the given position. + * @method LA + */ + LT: function(index){ + + //lookahead first to prime the token buffer + this.LA(index); + + //now find the token, subtract one because _ltIndex is already at the next index + return this._lt[this._ltIndex+index-1]; + }, + + /** + * Returns the token type for the next token in the stream without + * consuming it. + * @return {int} The token type of the next token in the stream. + * @method peek + */ + peek: function(){ + return this.LA(1); + }, + + /** + * Returns the actual token object for the last consumed token. + * @return {Token} The token object for the last consumed token. + * @method token + */ + token: function(){ + return this._token; + }, + + /** + * Returns the name of the token for the given token type. + * @param {int} tokenType The type of token to get the name of. + * @return {String} The name of the token or "UNKNOWN_TOKEN" for any + * invalid token type. + * @method tokenName + */ + tokenName: function(tokenType){ + if (tokenType < 0 || tokenType > this._tokenData.length){ + return "UNKNOWN_TOKEN"; + } else { + return this._tokenData[tokenType].name; + } + }, + + /** + * Returns the token type value for the given token name. + * @param {String} tokenName The name of the token whose value should be returned. + * @return {int} The token type value for the given token name or -1 + * for an unknown token. + * @method tokenName + */ + tokenType: function(tokenName){ + return this._tokenData[tokenName] || -1; + }, + + /** + * Returns the last consumed token to the token stream. + * @method unget + */ + unget: function(){ + //if (this._ltIndex > -1){ + if (this._ltIndexCache.length){ + this._ltIndex -= this._ltIndexCache.pop();//--; + this._token = this._lt[this._ltIndex - 1]; + } else { + throw new Error("Too much lookahead."); + } + } + +}; + + + + +parserlib.util = { +StringReader: StringReader, +SyntaxError : SyntaxError, +SyntaxUnit : SyntaxUnit, +EventTarget : EventTarget, +TokenStreamBase : TokenStreamBase +}; +})(); + + +/* +Parser-Lib +Copyright (c) 2009-2011 Nicholas C. Zakas. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ +/* Version v0.1.9, Build time: 23-July-2012 10:52:31 */ +(function(){ +var EventTarget = parserlib.util.EventTarget, +TokenStreamBase = parserlib.util.TokenStreamBase, +StringReader = parserlib.util.StringReader, +SyntaxError = parserlib.util.SyntaxError, +SyntaxUnit = parserlib.util.SyntaxUnit; + + +var Colors = { + aliceblue :"#f0f8ff", + antiquewhite :"#faebd7", + aqua :"#00ffff", + aquamarine :"#7fffd4", + azure :"#f0ffff", + beige :"#f5f5dc", + bisque :"#ffe4c4", + black :"#000000", + blanchedalmond :"#ffebcd", + blue :"#0000ff", + blueviolet :"#8a2be2", + brown :"#a52a2a", + burlywood :"#deb887", + cadetblue :"#5f9ea0", + chartreuse :"#7fff00", + chocolate :"#d2691e", + coral :"#ff7f50", + cornflowerblue :"#6495ed", + cornsilk :"#fff8dc", + crimson :"#dc143c", + cyan :"#00ffff", + darkblue :"#00008b", + darkcyan :"#008b8b", + darkgoldenrod :"#b8860b", + darkgray :"#a9a9a9", + darkgreen :"#006400", + darkkhaki :"#bdb76b", + darkmagenta :"#8b008b", + darkolivegreen :"#556b2f", + darkorange :"#ff8c00", + darkorchid :"#9932cc", + darkred :"#8b0000", + darksalmon :"#e9967a", + darkseagreen :"#8fbc8f", + darkslateblue :"#483d8b", + darkslategray :"#2f4f4f", + darkturquoise :"#00ced1", + darkviolet :"#9400d3", + deeppink :"#ff1493", + deepskyblue :"#00bfff", + dimgray :"#696969", + dodgerblue :"#1e90ff", + firebrick :"#b22222", + floralwhite :"#fffaf0", + forestgreen :"#228b22", + fuchsia :"#ff00ff", + gainsboro :"#dcdcdc", + ghostwhite :"#f8f8ff", + gold :"#ffd700", + goldenrod :"#daa520", + gray :"#808080", + green :"#008000", + greenyellow :"#adff2f", + honeydew :"#f0fff0", + hotpink :"#ff69b4", + indianred :"#cd5c5c", + indigo :"#4b0082", + ivory :"#fffff0", + khaki :"#f0e68c", + lavender :"#e6e6fa", + lavenderblush :"#fff0f5", + lawngreen :"#7cfc00", + lemonchiffon :"#fffacd", + lightblue :"#add8e6", + lightcoral :"#f08080", + lightcyan :"#e0ffff", + lightgoldenrodyellow :"#fafad2", + lightgray :"#d3d3d3", + lightgreen :"#90ee90", + lightpink :"#ffb6c1", + lightsalmon :"#ffa07a", + lightseagreen :"#20b2aa", + lightskyblue :"#87cefa", + lightslategray :"#778899", + lightsteelblue :"#b0c4de", + lightyellow :"#ffffe0", + lime :"#00ff00", + limegreen :"#32cd32", + linen :"#faf0e6", + magenta :"#ff00ff", + maroon :"#800000", + mediumaquamarine:"#66cdaa", + mediumblue :"#0000cd", + mediumorchid :"#ba55d3", + mediumpurple :"#9370d8", + mediumseagreen :"#3cb371", + mediumslateblue :"#7b68ee", + mediumspringgreen :"#00fa9a", + mediumturquoise :"#48d1cc", + mediumvioletred :"#c71585", + midnightblue :"#191970", + mintcream :"#f5fffa", + mistyrose :"#ffe4e1", + moccasin :"#ffe4b5", + navajowhite :"#ffdead", + navy :"#000080", + oldlace :"#fdf5e6", + olive :"#808000", + olivedrab :"#6b8e23", + orange :"#ffa500", + orangered :"#ff4500", + orchid :"#da70d6", + palegoldenrod :"#eee8aa", + palegreen :"#98fb98", + paleturquoise :"#afeeee", + palevioletred :"#d87093", + papayawhip :"#ffefd5", + peachpuff :"#ffdab9", + peru :"#cd853f", + pink :"#ffc0cb", + plum :"#dda0dd", + powderblue :"#b0e0e6", + purple :"#800080", + red :"#ff0000", + rosybrown :"#bc8f8f", + royalblue :"#4169e1", + saddlebrown :"#8b4513", + salmon :"#fa8072", + sandybrown :"#f4a460", + seagreen :"#2e8b57", + seashell :"#fff5ee", + sienna :"#a0522d", + silver :"#c0c0c0", + skyblue :"#87ceeb", + slateblue :"#6a5acd", + slategray :"#708090", + snow :"#fffafa", + springgreen :"#00ff7f", + steelblue :"#4682b4", + tan :"#d2b48c", + teal :"#008080", + thistle :"#d8bfd8", + tomato :"#ff6347", + turquoise :"#40e0d0", + violet :"#ee82ee", + wheat :"#f5deb3", + white :"#ffffff", + whitesmoke :"#f5f5f5", + yellow :"#ffff00", + yellowgreen :"#9acd32" +}; +/*global SyntaxUnit, Parser*/ +/** + * Represents a selector combinator (whitespace, +, >). + * @namespace parserlib.css + * @class Combinator + * @extends parserlib.util.SyntaxUnit + * @constructor + * @param {String} text The text representation of the unit. + * @param {int} line The line of text on which the unit resides. + * @param {int} col The column of text on which the unit resides. + */ +function Combinator(text, line, col){ + + SyntaxUnit.call(this, text, line, col, Parser.COMBINATOR_TYPE); + + /** + * The type of modifier. + * @type String + * @property type + */ + this.type = "unknown"; + + //pretty simple + if (/^\s+$/.test(text)){ + this.type = "descendant"; + } else if (text == ">"){ + this.type = "child"; + } else if (text == "+"){ + this.type = "adjacent-sibling"; + } else if (text == "~"){ + this.type = "sibling"; + } + +} + +Combinator.prototype = new SyntaxUnit(); +Combinator.prototype.constructor = Combinator; + + +/*global SyntaxUnit, Parser*/ +/** + * Represents a media feature, such as max-width:500. + * @namespace parserlib.css + * @class MediaFeature + * @extends parserlib.util.SyntaxUnit + * @constructor + * @param {SyntaxUnit} name The name of the feature. + * @param {SyntaxUnit} value The value of the feature or null if none. + */ +function MediaFeature(name, value){ + + SyntaxUnit.call(this, "(" + name + (value !== null ? ":" + value : "") + ")", name.startLine, name.startCol, Parser.MEDIA_FEATURE_TYPE); + + /** + * The name of the media feature + * @type String + * @property name + */ + this.name = name; + + /** + * The value for the feature or null if there is none. + * @type SyntaxUnit + * @property value + */ + this.value = value; +} + +MediaFeature.prototype = new SyntaxUnit(); +MediaFeature.prototype.constructor = MediaFeature; + + +/*global SyntaxUnit, Parser*/ +/** + * Represents an individual media query. + * @namespace parserlib.css + * @class MediaQuery + * @extends parserlib.util.SyntaxUnit + * @constructor + * @param {String} modifier The modifier "not" or "only" (or null). + * @param {String} mediaType The type of media (i.e., "print"). + * @param {Array} parts Array of selectors parts making up this selector. + * @param {int} line The line of text on which the unit resides. + * @param {int} col The column of text on which the unit resides. + */ +function MediaQuery(modifier, mediaType, features, line, col){ + + SyntaxUnit.call(this, (modifier ? modifier + " ": "") + (mediaType ? mediaType + " " : "") + features.join(" and "), line, col, Parser.MEDIA_QUERY_TYPE); + + /** + * The media modifier ("not" or "only") + * @type String + * @property modifier + */ + this.modifier = modifier; + + /** + * The mediaType (i.e., "print") + * @type String + * @property mediaType + */ + this.mediaType = mediaType; + + /** + * The parts that make up the selector. + * @type Array + * @property features + */ + this.features = features; + +} + +MediaQuery.prototype = new SyntaxUnit(); +MediaQuery.prototype.constructor = MediaQuery; + + +/*global Tokens, TokenStream, SyntaxError, Properties, Validation, ValidationError, SyntaxUnit, + PropertyValue, PropertyValuePart, SelectorPart, SelectorSubPart, Selector, + PropertyName, Combinator, MediaFeature, MediaQuery, EventTarget */ + +/** + * A CSS3 parser. + * @namespace parserlib.css + * @class Parser + * @constructor + * @param {Object} options (Optional) Various options for the parser: + * starHack (true|false) to allow IE6 star hack as valid, + * underscoreHack (true|false) to interpret leading underscores + * as IE6-7 targeting for known properties, ieFilters (true|false) + * to indicate that IE < 8 filters should be accepted and not throw + * syntax errors. + */ +function Parser(options){ + + //inherit event functionality + EventTarget.call(this); + + + this.options = options || {}; + + this._tokenStream = null; +} + +//Static constants +Parser.DEFAULT_TYPE = 0; +Parser.COMBINATOR_TYPE = 1; +Parser.MEDIA_FEATURE_TYPE = 2; +Parser.MEDIA_QUERY_TYPE = 3; +Parser.PROPERTY_NAME_TYPE = 4; +Parser.PROPERTY_VALUE_TYPE = 5; +Parser.PROPERTY_VALUE_PART_TYPE = 6; +Parser.SELECTOR_TYPE = 7; +Parser.SELECTOR_PART_TYPE = 8; +Parser.SELECTOR_SUB_PART_TYPE = 9; + +Parser.prototype = function(){ + + var proto = new EventTarget(), //new prototype + prop, + additions = { + + //restore constructor + constructor: Parser, + + //instance constants - yuck + DEFAULT_TYPE : 0, + COMBINATOR_TYPE : 1, + MEDIA_FEATURE_TYPE : 2, + MEDIA_QUERY_TYPE : 3, + PROPERTY_NAME_TYPE : 4, + PROPERTY_VALUE_TYPE : 5, + PROPERTY_VALUE_PART_TYPE : 6, + SELECTOR_TYPE : 7, + SELECTOR_PART_TYPE : 8, + SELECTOR_SUB_PART_TYPE : 9, + + //----------------------------------------------------------------- + // Grammar + //----------------------------------------------------------------- + + _stylesheet: function(){ + + /* + * stylesheet + * : [ CHARSET_SYM S* STRING S* ';' ]? + * [S|CDO|CDC]* [ import [S|CDO|CDC]* ]* + * [ namespace [S|CDO|CDC]* ]* + * [ [ ruleset | media | page | font_face | keyframes ] [S|CDO|CDC]* ]* + * ; + */ + + var tokenStream = this._tokenStream, + charset = null, + count, + token, + tt; + + this.fire("startstylesheet"); + + //try to read character set + this._charset(); + + this._skipCruft(); + + //try to read imports - may be more than one + while (tokenStream.peek() == Tokens.IMPORT_SYM){ + this._import(); + this._skipCruft(); + } + + //try to read namespaces - may be more than one + while (tokenStream.peek() == Tokens.NAMESPACE_SYM){ + this._namespace(); + this._skipCruft(); + } + + //get the next token + tt = tokenStream.peek(); + + //try to read the rest + while(tt > Tokens.EOF){ + + try { + + switch(tt){ + case Tokens.MEDIA_SYM: + this._media(); + this._skipCruft(); + break; + case Tokens.PAGE_SYM: + this._page(); + this._skipCruft(); + break; + case Tokens.FONT_FACE_SYM: + this._font_face(); + this._skipCruft(); + break; + case Tokens.KEYFRAMES_SYM: + this._keyframes(); + this._skipCruft(); + break; + case Tokens.UNKNOWN_SYM: //unknown @ rule + tokenStream.get(); + if (!this.options.strict){ + + //fire error event + this.fire({ + type: "error", + error: null, + message: "Unknown @ rule: " + tokenStream.LT(0).value + ".", + line: tokenStream.LT(0).startLine, + col: tokenStream.LT(0).startCol + }); + + //skip braces + count=0; + while (tokenStream.advance([Tokens.LBRACE, Tokens.RBRACE]) == Tokens.LBRACE){ + count++; //keep track of nesting depth + } + + while(count){ + tokenStream.advance([Tokens.RBRACE]); + count--; + } + + } else { + //not a syntax error, rethrow it + throw new SyntaxError("Unknown @ rule.", tokenStream.LT(0).startLine, tokenStream.LT(0).startCol); + } + break; + case Tokens.S: + this._readWhitespace(); + break; + default: + if(!this._ruleset()){ + + //error handling for known issues + switch(tt){ + case Tokens.CHARSET_SYM: + token = tokenStream.LT(1); + this._charset(false); + throw new SyntaxError("@charset not allowed here.", token.startLine, token.startCol); + case Tokens.IMPORT_SYM: + token = tokenStream.LT(1); + this._import(false); + throw new SyntaxError("@import not allowed here.", token.startLine, token.startCol); + case Tokens.NAMESPACE_SYM: + token = tokenStream.LT(1); + this._namespace(false); + throw new SyntaxError("@namespace not allowed here.", token.startLine, token.startCol); + default: + tokenStream.get(); //get the last token + this._unexpectedToken(tokenStream.token()); + } + + } + } + } catch(ex) { + if (ex instanceof SyntaxError && !this.options.strict){ + this.fire({ + type: "error", + error: ex, + message: ex.message, + line: ex.line, + col: ex.col + }); + } else { + throw ex; + } + } + + tt = tokenStream.peek(); + } + + if (tt != Tokens.EOF){ + this._unexpectedToken(tokenStream.token()); + } + + this.fire("endstylesheet"); + }, + + _charset: function(emit){ + var tokenStream = this._tokenStream, + charset, + token, + line, + col; + + if (tokenStream.match(Tokens.CHARSET_SYM)){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + tokenStream.mustMatch(Tokens.STRING); + + token = tokenStream.token(); + charset = token.value; + + this._readWhitespace(); + tokenStream.mustMatch(Tokens.SEMICOLON); + + if (emit !== false){ + this.fire({ + type: "charset", + charset:charset, + line: line, + col: col + }); + } + } + }, + + _import: function(emit){ + /* + * import + * : IMPORT_SYM S* + * [STRING|URI] S* media_query_list? ';' S* + */ + + var tokenStream = this._tokenStream, + tt, + uri, + importToken, + mediaList = []; + + //read import symbol + tokenStream.mustMatch(Tokens.IMPORT_SYM); + importToken = tokenStream.token(); + this._readWhitespace(); + + tokenStream.mustMatch([Tokens.STRING, Tokens.URI]); + + //grab the URI value + uri = tokenStream.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/, "$1"); + + this._readWhitespace(); + + mediaList = this._media_query_list(); + + //must end with a semicolon + tokenStream.mustMatch(Tokens.SEMICOLON); + this._readWhitespace(); + + if (emit !== false){ + this.fire({ + type: "import", + uri: uri, + media: mediaList, + line: importToken.startLine, + col: importToken.startCol + }); + } + + }, + + _namespace: function(emit){ + /* + * namespace + * : NAMESPACE_SYM S* [namespace_prefix S*]? [STRING|URI] S* ';' S* + */ + + var tokenStream = this._tokenStream, + line, + col, + prefix, + uri; + + //read import symbol + tokenStream.mustMatch(Tokens.NAMESPACE_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + this._readWhitespace(); + + //it's a namespace prefix - no _namespace_prefix() method because it's just an IDENT + if (tokenStream.match(Tokens.IDENT)){ + prefix = tokenStream.token().value; + this._readWhitespace(); + } + + tokenStream.mustMatch([Tokens.STRING, Tokens.URI]); + /*if (!tokenStream.match(Tokens.STRING)){ + tokenStream.mustMatch(Tokens.URI); + }*/ + + //grab the URI value + uri = tokenStream.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/, "$1"); + + this._readWhitespace(); + + //must end with a semicolon + tokenStream.mustMatch(Tokens.SEMICOLON); + this._readWhitespace(); + + if (emit !== false){ + this.fire({ + type: "namespace", + prefix: prefix, + uri: uri, + line: line, + col: col + }); + } + + }, + + _media: function(){ + /* + * media + * : MEDIA_SYM S* media_query_list S* '{' S* ruleset* '}' S* + * ; + */ + var tokenStream = this._tokenStream, + line, + col, + mediaList;// = []; + + //look for @media + tokenStream.mustMatch(Tokens.MEDIA_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + + mediaList = this._media_query_list(); + + tokenStream.mustMatch(Tokens.LBRACE); + this._readWhitespace(); + + this.fire({ + type: "startmedia", + media: mediaList, + line: line, + col: col + }); + + while(true) { + if (tokenStream.peek() == Tokens.PAGE_SYM){ + this._page(); + } else if (!this._ruleset()){ + break; + } + } + + tokenStream.mustMatch(Tokens.RBRACE); + this._readWhitespace(); + + this.fire({ + type: "endmedia", + media: mediaList, + line: line, + col: col + }); + }, + + + //CSS3 Media Queries + _media_query_list: function(){ + /* + * media_query_list + * : S* [media_query [ ',' S* media_query ]* ]? + * ; + */ + var tokenStream = this._tokenStream, + mediaList = []; + + + this._readWhitespace(); + + if (tokenStream.peek() == Tokens.IDENT || tokenStream.peek() == Tokens.LPAREN){ + mediaList.push(this._media_query()); + } + + while(tokenStream.match(Tokens.COMMA)){ + this._readWhitespace(); + mediaList.push(this._media_query()); + } + + return mediaList; + }, + + /* + * Note: "expression" in the grammar maps to the _media_expression + * method. + + */ + _media_query: function(){ + /* + * media_query + * : [ONLY | NOT]? S* media_type S* [ AND S* expression ]* + * | expression [ AND S* expression ]* + * ; + */ + var tokenStream = this._tokenStream, + type = null, + ident = null, + token = null, + expressions = []; + + if (tokenStream.match(Tokens.IDENT)){ + ident = tokenStream.token().value.toLowerCase(); + + //since there's no custom tokens for these, need to manually check + if (ident != "only" && ident != "not"){ + tokenStream.unget(); + ident = null; + } else { + token = tokenStream.token(); + } + } + + this._readWhitespace(); + + if (tokenStream.peek() == Tokens.IDENT){ + type = this._media_type(); + if (token === null){ + token = tokenStream.token(); + } + } else if (tokenStream.peek() == Tokens.LPAREN){ + if (token === null){ + token = tokenStream.LT(1); + } + expressions.push(this._media_expression()); + } + + if (type === null && expressions.length === 0){ + return null; + } else { + this._readWhitespace(); + while (tokenStream.match(Tokens.IDENT)){ + if (tokenStream.token().value.toLowerCase() != "and"){ + this._unexpectedToken(tokenStream.token()); + } + + this._readWhitespace(); + expressions.push(this._media_expression()); + } + } + + return new MediaQuery(ident, type, expressions, token.startLine, token.startCol); + }, + + //CSS3 Media Queries + _media_type: function(){ + /* + * media_type + * : IDENT + * ; + */ + return this._media_feature(); + }, + + /** + * Note: in CSS3 Media Queries, this is called "expression". + * Renamed here to avoid conflict with CSS3 Selectors + * definition of "expression". Also note that "expr" in the + * grammar now maps to "expression" from CSS3 selectors. + * @method _media_expression + * @private + */ + _media_expression: function(){ + /* + * expression + * : '(' S* media_feature S* [ ':' S* expr ]? ')' S* + * ; + */ + var tokenStream = this._tokenStream, + feature = null, + token, + expression = null; + + tokenStream.mustMatch(Tokens.LPAREN); + + feature = this._media_feature(); + this._readWhitespace(); + + if (tokenStream.match(Tokens.COLON)){ + this._readWhitespace(); + token = tokenStream.LT(1); + expression = this._expression(); + } + + tokenStream.mustMatch(Tokens.RPAREN); + this._readWhitespace(); + + return new MediaFeature(feature, (expression ? new SyntaxUnit(expression, token.startLine, token.startCol) : null)); + }, + + //CSS3 Media Queries + _media_feature: function(){ + /* + * media_feature + * : IDENT + * ; + */ + var tokenStream = this._tokenStream; + + tokenStream.mustMatch(Tokens.IDENT); + + return SyntaxUnit.fromToken(tokenStream.token()); + }, + + //CSS3 Paged Media + _page: function(){ + /* + * page: + * PAGE_SYM S* IDENT? pseudo_page? S* + * '{' S* [ declaration | margin ]? [ ';' S* [ declaration | margin ]? ]* '}' S* + * ; + */ + var tokenStream = this._tokenStream, + line, + col, + identifier = null, + pseudoPage = null; + + //look for @page + tokenStream.mustMatch(Tokens.PAGE_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + + if (tokenStream.match(Tokens.IDENT)){ + identifier = tokenStream.token().value; + + //The value 'auto' may not be used as a page name and MUST be treated as a syntax error. + if (identifier.toLowerCase() === "auto"){ + this._unexpectedToken(tokenStream.token()); + } + } + + //see if there's a colon upcoming + if (tokenStream.peek() == Tokens.COLON){ + pseudoPage = this._pseudo_page(); + } + + this._readWhitespace(); + + this.fire({ + type: "startpage", + id: identifier, + pseudo: pseudoPage, + line: line, + col: col + }); + + this._readDeclarations(true, true); + + this.fire({ + type: "endpage", + id: identifier, + pseudo: pseudoPage, + line: line, + col: col + }); + + }, + + //CSS3 Paged Media + _margin: function(){ + /* + * margin : + * margin_sym S* '{' declaration [ ';' S* declaration? ]* '}' S* + * ; + */ + var tokenStream = this._tokenStream, + line, + col, + marginSym = this._margin_sym(); + + if (marginSym){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this.fire({ + type: "startpagemargin", + margin: marginSym, + line: line, + col: col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endpagemargin", + margin: marginSym, + line: line, + col: col + }); + return true; + } else { + return false; + } + }, + + //CSS3 Paged Media + _margin_sym: function(){ + + /* + * margin_sym : + * TOPLEFTCORNER_SYM | + * TOPLEFT_SYM | + * TOPCENTER_SYM | + * TOPRIGHT_SYM | + * TOPRIGHTCORNER_SYM | + * BOTTOMLEFTCORNER_SYM | + * BOTTOMLEFT_SYM | + * BOTTOMCENTER_SYM | + * BOTTOMRIGHT_SYM | + * BOTTOMRIGHTCORNER_SYM | + * LEFTTOP_SYM | + * LEFTMIDDLE_SYM | + * LEFTBOTTOM_SYM | + * RIGHTTOP_SYM | + * RIGHTMIDDLE_SYM | + * RIGHTBOTTOM_SYM + * ; + */ + + var tokenStream = this._tokenStream; + + if(tokenStream.match([Tokens.TOPLEFTCORNER_SYM, Tokens.TOPLEFT_SYM, + Tokens.TOPCENTER_SYM, Tokens.TOPRIGHT_SYM, Tokens.TOPRIGHTCORNER_SYM, + Tokens.BOTTOMLEFTCORNER_SYM, Tokens.BOTTOMLEFT_SYM, + Tokens.BOTTOMCENTER_SYM, Tokens.BOTTOMRIGHT_SYM, + Tokens.BOTTOMRIGHTCORNER_SYM, Tokens.LEFTTOP_SYM, + Tokens.LEFTMIDDLE_SYM, Tokens.LEFTBOTTOM_SYM, Tokens.RIGHTTOP_SYM, + Tokens.RIGHTMIDDLE_SYM, Tokens.RIGHTBOTTOM_SYM])) + { + return SyntaxUnit.fromToken(tokenStream.token()); + } else { + return null; + } + + }, + + _pseudo_page: function(){ + /* + * pseudo_page + * : ':' IDENT + * ; + */ + + var tokenStream = this._tokenStream; + + tokenStream.mustMatch(Tokens.COLON); + tokenStream.mustMatch(Tokens.IDENT); + + //TODO: CSS3 Paged Media says only "left", "center", and "right" are allowed + + return tokenStream.token().value; + }, + + _font_face: function(){ + /* + * font_face + * : FONT_FACE_SYM S* + * '{' S* declaration [ ';' S* declaration ]* '}' S* + * ; + */ + var tokenStream = this._tokenStream, + line, + col; + + //look for @page + tokenStream.mustMatch(Tokens.FONT_FACE_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + + this.fire({ + type: "startfontface", + line: line, + col: col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endfontface", + line: line, + col: col + }); + }, + + _operator: function(){ + + /* + * operator + * : '/' S* | ',' S* | /( empty )/ + * ; + */ + + var tokenStream = this._tokenStream, + token = null; + + if (tokenStream.match([Tokens.SLASH, Tokens.COMMA])){ + token = tokenStream.token(); + this._readWhitespace(); + } + return token ? PropertyValuePart.fromToken(token) : null; + + }, + + _combinator: function(){ + + /* + * combinator + * : PLUS S* | GREATER S* | TILDE S* | S+ + * ; + */ + + var tokenStream = this._tokenStream, + value = null, + token; + + if(tokenStream.match([Tokens.PLUS, Tokens.GREATER, Tokens.TILDE])){ + token = tokenStream.token(); + value = new Combinator(token.value, token.startLine, token.startCol); + this._readWhitespace(); + } + + return value; + }, + + _unary_operator: function(){ + + /* + * unary_operator + * : '-' | '+' + * ; + */ + + var tokenStream = this._tokenStream; + + if (tokenStream.match([Tokens.MINUS, Tokens.PLUS])){ + return tokenStream.token().value; + } else { + return null; + } + }, + + _property: function(){ + + /* + * property + * : IDENT S* + * ; + */ + + var tokenStream = this._tokenStream, + value = null, + hack = null, + tokenValue, + token, + line, + col; + + //check for star hack - throws error if not allowed + if (tokenStream.peek() == Tokens.STAR && this.options.starHack){ + tokenStream.get(); + token = tokenStream.token(); + hack = token.value; + line = token.startLine; + col = token.startCol; + } + + if(tokenStream.match(Tokens.IDENT)){ + token = tokenStream.token(); + tokenValue = token.value; + + //check for underscore hack - no error if not allowed because it's valid CSS syntax + if (tokenValue.charAt(0) == "_" && this.options.underscoreHack){ + hack = "_"; + tokenValue = tokenValue.substring(1); + } + + value = new PropertyName(tokenValue, hack, (line||token.startLine), (col||token.startCol)); + this._readWhitespace(); + } + + return value; + }, + + //Augmented with CSS3 Selectors + _ruleset: function(){ + /* + * ruleset + * : selectors_group + * '{' S* declaration? [ ';' S* declaration? ]* '}' S* + * ; + */ + + var tokenStream = this._tokenStream, + tt, + selectors; + + + /* + * Error Recovery: If even a single selector fails to parse, + * then the entire ruleset should be thrown away. + */ + try { + selectors = this._selectors_group(); + } catch (ex){ + if (ex instanceof SyntaxError && !this.options.strict){ + + //fire error event + this.fire({ + type: "error", + error: ex, + message: ex.message, + line: ex.line, + col: ex.col + }); + + //skip over everything until closing brace + tt = tokenStream.advance([Tokens.RBRACE]); + if (tt == Tokens.RBRACE){ + //if there's a right brace, the rule is finished so don't do anything + } else { + //otherwise, rethrow the error because it wasn't handled properly + throw ex; + } + + } else { + //not a syntax error, rethrow it + throw ex; + } + + //trigger parser to continue + return true; + } + + //if it got here, all selectors parsed + if (selectors){ + + this.fire({ + type: "startrule", + selectors: selectors, + line: selectors[0].line, + col: selectors[0].col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endrule", + selectors: selectors, + line: selectors[0].line, + col: selectors[0].col + }); + + } + + return selectors; + + }, + + //CSS3 Selectors + _selectors_group: function(){ + + /* + * selectors_group + * : selector [ COMMA S* selector ]* + * ; + */ + var tokenStream = this._tokenStream, + selectors = [], + selector; + + selector = this._selector(); + if (selector !== null){ + + selectors.push(selector); + while(tokenStream.match(Tokens.COMMA)){ + this._readWhitespace(); + selector = this._selector(); + if (selector !== null){ + selectors.push(selector); + } else { + this._unexpectedToken(tokenStream.LT(1)); + } + } + } + + return selectors.length ? selectors : null; + }, + + //CSS3 Selectors + _selector: function(){ + /* + * selector + * : simple_selector_sequence [ combinator simple_selector_sequence ]* + * ; + */ + + var tokenStream = this._tokenStream, + selector = [], + nextSelector = null, + combinator = null, + ws = null; + + //if there's no simple selector, then there's no selector + nextSelector = this._simple_selector_sequence(); + if (nextSelector === null){ + return null; + } + + selector.push(nextSelector); + + do { + + //look for a combinator + combinator = this._combinator(); + + if (combinator !== null){ + selector.push(combinator); + nextSelector = this._simple_selector_sequence(); + + //there must be a next selector + if (nextSelector === null){ + this._unexpectedToken(tokenStream.LT(1)); + } else { + + //nextSelector is an instance of SelectorPart + selector.push(nextSelector); + } + } else { + + //if there's not whitespace, we're done + if (this._readWhitespace()){ + + //add whitespace separator + ws = new Combinator(tokenStream.token().value, tokenStream.token().startLine, tokenStream.token().startCol); + + //combinator is not required + combinator = this._combinator(); + + //selector is required if there's a combinator + nextSelector = this._simple_selector_sequence(); + if (nextSelector === null){ + if (combinator !== null){ + this._unexpectedToken(tokenStream.LT(1)); + } + } else { + + if (combinator !== null){ + selector.push(combinator); + } else { + selector.push(ws); + } + + selector.push(nextSelector); + } + } else { + break; + } + + } + } while(true); + + return new Selector(selector, selector[0].line, selector[0].col); + }, + + //CSS3 Selectors + _simple_selector_sequence: function(){ + /* + * simple_selector_sequence + * : [ type_selector | universal ] + * [ HASH | class | attrib | pseudo | negation ]* + * | [ HASH | class | attrib | pseudo | negation ]+ + * ; + */ + + var tokenStream = this._tokenStream, + + //parts of a simple selector + elementName = null, + modifiers = [], + + //complete selector text + selectorText= "", + + //the different parts after the element name to search for + components = [ + //HASH + function(){ + return tokenStream.match(Tokens.HASH) ? + new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) : + null; + }, + this._class, + this._attrib, + this._pseudo, + this._negation + ], + i = 0, + len = components.length, + component = null, + found = false, + line, + col; + + + //get starting line and column for the selector + line = tokenStream.LT(1).startLine; + col = tokenStream.LT(1).startCol; + + elementName = this._type_selector(); + if (!elementName){ + elementName = this._universal(); + } + + if (elementName !== null){ + selectorText += elementName; + } + + while(true){ + + //whitespace means we're done + if (tokenStream.peek() === Tokens.S){ + break; + } + + //check for each component + while(i < len && component === null){ + component = components[i++].call(this); + } + + if (component === null){ + + //we don't have a selector + if (selectorText === ""){ + return null; + } else { + break; + } + } else { + i = 0; + modifiers.push(component); + selectorText += component.toString(); + component = null; + } + } + + + return selectorText !== "" ? + new SelectorPart(elementName, modifiers, selectorText, line, col) : + null; + }, + + //CSS3 Selectors + _type_selector: function(){ + /* + * type_selector + * : [ namespace_prefix ]? element_name + * ; + */ + + var tokenStream = this._tokenStream, + ns = this._namespace_prefix(), + elementName = this._element_name(); + + if (!elementName){ + /* + * Need to back out the namespace that was read due to both + * type_selector and universal reading namespace_prefix + * first. Kind of hacky, but only way I can figure out + * right now how to not change the grammar. + */ + if (ns){ + tokenStream.unget(); + if (ns.length > 1){ + tokenStream.unget(); + } + } + + return null; + } else { + if (ns){ + elementName.text = ns + elementName.text; + elementName.col -= ns.length; + } + return elementName; + } + }, + + //CSS3 Selectors + _class: function(){ + /* + * class + * : '.' IDENT + * ; + */ + + var tokenStream = this._tokenStream, + token; + + if (tokenStream.match(Tokens.DOT)){ + tokenStream.mustMatch(Tokens.IDENT); + token = tokenStream.token(); + return new SelectorSubPart("." + token.value, "class", token.startLine, token.startCol - 1); + } else { + return null; + } + + }, + + //CSS3 Selectors + _element_name: function(){ + /* + * element_name + * : IDENT + * ; + */ + + var tokenStream = this._tokenStream, + token; + + if (tokenStream.match(Tokens.IDENT)){ + token = tokenStream.token(); + return new SelectorSubPart(token.value, "elementName", token.startLine, token.startCol); + + } else { + return null; + } + }, + + //CSS3 Selectors + _namespace_prefix: function(){ + /* + * namespace_prefix + * : [ IDENT | '*' ]? '|' + * ; + */ + var tokenStream = this._tokenStream, + value = ""; + + //verify that this is a namespace prefix + if (tokenStream.LA(1) === Tokens.PIPE || tokenStream.LA(2) === Tokens.PIPE){ + + if(tokenStream.match([Tokens.IDENT, Tokens.STAR])){ + value += tokenStream.token().value; + } + + tokenStream.mustMatch(Tokens.PIPE); + value += "|"; + + } + + return value.length ? value : null; + }, + + //CSS3 Selectors + _universal: function(){ + /* + * universal + * : [ namespace_prefix ]? '*' + * ; + */ + var tokenStream = this._tokenStream, + value = "", + ns; + + ns = this._namespace_prefix(); + if(ns){ + value += ns; + } + + if(tokenStream.match(Tokens.STAR)){ + value += "*"; + } + + return value.length ? value : null; + + }, + + //CSS3 Selectors + _attrib: function(){ + /* + * attrib + * : '[' S* [ namespace_prefix ]? IDENT S* + * [ [ PREFIXMATCH | + * SUFFIXMATCH | + * SUBSTRINGMATCH | + * '=' | + * INCLUDES | + * DASHMATCH ] S* [ IDENT | STRING ] S* + * ]? ']' + * ; + */ + + var tokenStream = this._tokenStream, + value = null, + ns, + token; + + if (tokenStream.match(Tokens.LBRACKET)){ + token = tokenStream.token(); + value = token.value; + value += this._readWhitespace(); + + ns = this._namespace_prefix(); + + if (ns){ + value += ns; + } + + tokenStream.mustMatch(Tokens.IDENT); + value += tokenStream.token().value; + value += this._readWhitespace(); + + if(tokenStream.match([Tokens.PREFIXMATCH, Tokens.SUFFIXMATCH, Tokens.SUBSTRINGMATCH, + Tokens.EQUALS, Tokens.INCLUDES, Tokens.DASHMATCH])){ + + value += tokenStream.token().value; + value += this._readWhitespace(); + + tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]); + value += tokenStream.token().value; + value += this._readWhitespace(); + } + + tokenStream.mustMatch(Tokens.RBRACKET); + + return new SelectorSubPart(value + "]", "attribute", token.startLine, token.startCol); + } else { + return null; + } + }, + + //CSS3 Selectors + _pseudo: function(){ + + /* + * pseudo + * : ':' ':'? [ IDENT | functional_pseudo ] + * ; + */ + + var tokenStream = this._tokenStream, + pseudo = null, + colons = ":", + line, + col; + + if (tokenStream.match(Tokens.COLON)){ + + if (tokenStream.match(Tokens.COLON)){ + colons += ":"; + } + + if (tokenStream.match(Tokens.IDENT)){ + pseudo = tokenStream.token().value; + line = tokenStream.token().startLine; + col = tokenStream.token().startCol - colons.length; + } else if (tokenStream.peek() == Tokens.FUNCTION){ + line = tokenStream.LT(1).startLine; + col = tokenStream.LT(1).startCol - colons.length; + pseudo = this._functional_pseudo(); + } + + if (pseudo){ + pseudo = new SelectorSubPart(colons + pseudo, "pseudo", line, col); + } + } + + return pseudo; + }, + + //CSS3 Selectors + _functional_pseudo: function(){ + /* + * functional_pseudo + * : FUNCTION S* expression ')' + * ; + */ + + var tokenStream = this._tokenStream, + value = null; + + if(tokenStream.match(Tokens.FUNCTION)){ + value = tokenStream.token().value; + value += this._readWhitespace(); + value += this._expression(); + tokenStream.mustMatch(Tokens.RPAREN); + value += ")"; + } + + return value; + }, + + //CSS3 Selectors + _expression: function(){ + /* + * expression + * : [ [ PLUS | '-' | DIMENSION | NUMBER | STRING | IDENT ] S* ]+ + * ; + */ + + var tokenStream = this._tokenStream, + value = ""; + + while(tokenStream.match([Tokens.PLUS, Tokens.MINUS, Tokens.DIMENSION, + Tokens.NUMBER, Tokens.STRING, Tokens.IDENT, Tokens.LENGTH, + Tokens.FREQ, Tokens.ANGLE, Tokens.TIME, + Tokens.RESOLUTION])){ + + value += tokenStream.token().value; + value += this._readWhitespace(); + } + + return value.length ? value : null; + + }, + + //CSS3 Selectors + _negation: function(){ + /* + * negation + * : NOT S* negation_arg S* ')' + * ; + */ + + var tokenStream = this._tokenStream, + line, + col, + value = "", + arg, + subpart = null; + + if (tokenStream.match(Tokens.NOT)){ + value = tokenStream.token().value; + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + value += this._readWhitespace(); + arg = this._negation_arg(); + value += arg; + value += this._readWhitespace(); + tokenStream.match(Tokens.RPAREN); + value += tokenStream.token().value; + + subpart = new SelectorSubPart(value, "not", line, col); + subpart.args.push(arg); + } + + return subpart; + }, + + //CSS3 Selectors + _negation_arg: function(){ + /* + * negation_arg + * : type_selector | universal | HASH | class | attrib | pseudo + * ; + */ + + var tokenStream = this._tokenStream, + args = [ + this._type_selector, + this._universal, + function(){ + return tokenStream.match(Tokens.HASH) ? + new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) : + null; + }, + this._class, + this._attrib, + this._pseudo + ], + arg = null, + i = 0, + len = args.length, + elementName, + line, + col, + part; + + line = tokenStream.LT(1).startLine; + col = tokenStream.LT(1).startCol; + + while(i < len && arg === null){ + + arg = args[i].call(this); + i++; + } + + //must be a negation arg + if (arg === null){ + this._unexpectedToken(tokenStream.LT(1)); + } + + //it's an element name + if (arg.type == "elementName"){ + part = new SelectorPart(arg, [], arg.toString(), line, col); + } else { + part = new SelectorPart(null, [arg], arg.toString(), line, col); + } + + return part; + }, + + _declaration: function(){ + + /* + * declaration + * : property ':' S* expr prio? + * | /( empty )/ + * ; + */ + + var tokenStream = this._tokenStream, + property = null, + expr = null, + prio = null, + error = null, + invalid = null, + propertyName= ""; + + property = this._property(); + if (property !== null){ + + tokenStream.mustMatch(Tokens.COLON); + this._readWhitespace(); + + expr = this._expr(); + + //if there's no parts for the value, it's an error + if (!expr || expr.length === 0){ + this._unexpectedToken(tokenStream.LT(1)); + } + + prio = this._prio(); + + /* + * If hacks should be allowed, then only check the root + * property. If hacks should not be allowed, treat + * _property or *property as invalid properties. + */ + propertyName = property.toString(); + if (this.options.starHack && property.hack == "*" || + this.options.underscoreHack && property.hack == "_") { + + propertyName = property.text; + } + + try { + this._validateProperty(propertyName, expr); + } catch (ex) { + invalid = ex; + } + + this.fire({ + type: "property", + property: property, + value: expr, + important: prio, + line: property.line, + col: property.col, + invalid: invalid + }); + + return true; + } else { + return false; + } + }, + + _prio: function(){ + /* + * prio + * : IMPORTANT_SYM S* + * ; + */ + + var tokenStream = this._tokenStream, + result = tokenStream.match(Tokens.IMPORTANT_SYM); + + this._readWhitespace(); + return result; + }, + + _expr: function(){ + /* + * expr + * : term [ operator term ]* + * ; + */ + + var tokenStream = this._tokenStream, + values = [], + //valueParts = [], + value = null, + operator = null; + + value = this._term(); + if (value !== null){ + + values.push(value); + + do { + operator = this._operator(); + + //if there's an operator, keep building up the value parts + if (operator){ + values.push(operator); + } /*else { + //if there's not an operator, you have a full value + values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col)); + valueParts = []; + }*/ + + value = this._term(); + + if (value === null){ + break; + } else { + values.push(value); + } + } while(true); + } + + //cleanup + /*if (valueParts.length){ + values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col)); + }*/ + + return values.length > 0 ? new PropertyValue(values, values[0].line, values[0].col) : null; + }, + + _term: function(){ + + /* + * term + * : unary_operator? + * [ NUMBER S* | PERCENTAGE S* | LENGTH S* | ANGLE S* | + * TIME S* | FREQ S* | function | ie_function ] + * | STRING S* | IDENT S* | URI S* | UNICODERANGE S* | hexcolor + * ; + */ + + var tokenStream = this._tokenStream, + unary = null, + value = null, + token, + line, + col; + + //returns the operator or null + unary = this._unary_operator(); + if (unary !== null){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + } + + //exception for IE filters + if (tokenStream.peek() == Tokens.IE_FUNCTION && this.options.ieFilters){ + + value = this._ie_function(); + if (unary === null){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + } + + //see if there's a simple match + } else if (tokenStream.match([Tokens.NUMBER, Tokens.PERCENTAGE, Tokens.LENGTH, + Tokens.ANGLE, Tokens.TIME, + Tokens.FREQ, Tokens.STRING, Tokens.IDENT, Tokens.URI, Tokens.UNICODE_RANGE])){ + + value = tokenStream.token().value; + if (unary === null){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + } + this._readWhitespace(); + } else { + + //see if it's a color + token = this._hexcolor(); + if (token === null){ + + //if there's no unary, get the start of the next token for line/col info + if (unary === null){ + line = tokenStream.LT(1).startLine; + col = tokenStream.LT(1).startCol; + } + + //has to be a function + if (value === null){ + + /* + * This checks for alpha(opacity=0) style of IE + * functions. IE_FUNCTION only presents progid: style. + */ + if (tokenStream.LA(3) == Tokens.EQUALS && this.options.ieFilters){ + value = this._ie_function(); + } else { + value = this._function(); + } + } + + /*if (value === null){ + return null; + //throw new Error("Expected identifier at line " + tokenStream.token().startLine + ", character " + tokenStream.token().startCol + "."); + }*/ + + } else { + value = token.value; + if (unary === null){ + line = token.startLine; + col = token.startCol; + } + } + + } + + return value !== null ? + new PropertyValuePart(unary !== null ? unary + value : value, line, col) : + null; + + }, + + _function: function(){ + + /* + * function + * : FUNCTION S* expr ')' S* + * ; + */ + + var tokenStream = this._tokenStream, + functionText = null, + expr = null, + lt; + + if (tokenStream.match(Tokens.FUNCTION)){ + functionText = tokenStream.token().value; + this._readWhitespace(); + expr = this._expr(); + functionText += expr; + + //START: Horrible hack in case it's an IE filter + if (this.options.ieFilters && tokenStream.peek() == Tokens.EQUALS){ + do { + + if (this._readWhitespace()){ + functionText += tokenStream.token().value; + } + + //might be second time in the loop + if (tokenStream.LA(0) == Tokens.COMMA){ + functionText += tokenStream.token().value; + } + + tokenStream.match(Tokens.IDENT); + functionText += tokenStream.token().value; + + tokenStream.match(Tokens.EQUALS); + functionText += tokenStream.token().value; + + //functionText += this._term(); + lt = tokenStream.peek(); + while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){ + tokenStream.get(); + functionText += tokenStream.token().value; + lt = tokenStream.peek(); + } + } while(tokenStream.match([Tokens.COMMA, Tokens.S])); + } + + //END: Horrible Hack + + tokenStream.match(Tokens.RPAREN); + functionText += ")"; + this._readWhitespace(); + } + + return functionText; + }, + + _ie_function: function(){ + + /* (My own extension) + * ie_function + * : IE_FUNCTION S* IDENT '=' term [S* ','? IDENT '=' term]+ ')' S* + * ; + */ + + var tokenStream = this._tokenStream, + functionText = null, + expr = null, + lt; + + //IE function can begin like a regular function, too + if (tokenStream.match([Tokens.IE_FUNCTION, Tokens.FUNCTION])){ + functionText = tokenStream.token().value; + + do { + + if (this._readWhitespace()){ + functionText += tokenStream.token().value; + } + + //might be second time in the loop + if (tokenStream.LA(0) == Tokens.COMMA){ + functionText += tokenStream.token().value; + } + + tokenStream.match(Tokens.IDENT); + functionText += tokenStream.token().value; + + tokenStream.match(Tokens.EQUALS); + functionText += tokenStream.token().value; + + //functionText += this._term(); + lt = tokenStream.peek(); + while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){ + tokenStream.get(); + functionText += tokenStream.token().value; + lt = tokenStream.peek(); + } + } while(tokenStream.match([Tokens.COMMA, Tokens.S])); + + tokenStream.match(Tokens.RPAREN); + functionText += ")"; + this._readWhitespace(); + } + + return functionText; + }, + + _hexcolor: function(){ + /* + * There is a constraint on the color that it must + * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F]) + * after the "#"; e.g., "#000" is OK, but "#abcd" is not. + * + * hexcolor + * : HASH S* + * ; + */ + + var tokenStream = this._tokenStream, + token = null, + color; + + if(tokenStream.match(Tokens.HASH)){ + + //need to do some validation here + + token = tokenStream.token(); + color = token.value; + if (!/#[a-f0-9]{3,6}/i.test(color)){ + throw new SyntaxError("Expected a hex color but found '" + color + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); + } + this._readWhitespace(); + } + + return token; + }, + + //----------------------------------------------------------------- + // Animations methods + //----------------------------------------------------------------- + + _keyframes: function(){ + + /* + * keyframes: + * : KEYFRAMES_SYM S* keyframe_name S* '{' S* keyframe_rule* '}' { + * ; + */ + var tokenStream = this._tokenStream, + token, + tt, + name, + prefix = ""; + + tokenStream.mustMatch(Tokens.KEYFRAMES_SYM); + token = tokenStream.token(); + if (/^@\-([^\-]+)\-/.test(token.value)) { + prefix = RegExp.$1; + } + + this._readWhitespace(); + name = this._keyframe_name(); + + this._readWhitespace(); + tokenStream.mustMatch(Tokens.LBRACE); + + this.fire({ + type: "startkeyframes", + name: name, + prefix: prefix, + line: token.startLine, + col: token.startCol + }); + + this._readWhitespace(); + tt = tokenStream.peek(); + + //check for key + while(tt == Tokens.IDENT || tt == Tokens.PERCENTAGE) { + this._keyframe_rule(); + this._readWhitespace(); + tt = tokenStream.peek(); + } + + this.fire({ + type: "endkeyframes", + name: name, + prefix: prefix, + line: token.startLine, + col: token.startCol + }); + + this._readWhitespace(); + tokenStream.mustMatch(Tokens.RBRACE); + + }, + + _keyframe_name: function(){ + + /* + * keyframe_name: + * : IDENT + * | STRING + * ; + */ + var tokenStream = this._tokenStream, + token; + + tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]); + return SyntaxUnit.fromToken(tokenStream.token()); + }, + + _keyframe_rule: function(){ + + /* + * keyframe_rule: + * : key_list S* + * '{' S* declaration [ ';' S* declaration ]* '}' S* + * ; + */ + var tokenStream = this._tokenStream, + token, + keyList = this._key_list(); + + this.fire({ + type: "startkeyframerule", + keys: keyList, + line: keyList[0].line, + col: keyList[0].col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endkeyframerule", + keys: keyList, + line: keyList[0].line, + col: keyList[0].col + }); + + }, + + _key_list: function(){ + + /* + * key_list: + * : key [ S* ',' S* key]* + * ; + */ + var tokenStream = this._tokenStream, + token, + key, + keyList = []; + + //must be least one key + keyList.push(this._key()); + + this._readWhitespace(); + + while(tokenStream.match(Tokens.COMMA)){ + this._readWhitespace(); + keyList.push(this._key()); + this._readWhitespace(); + } + + return keyList; + }, + + _key: function(){ + /* + * There is a restriction that IDENT can be only "from" or "to". + * + * key + * : PERCENTAGE + * | IDENT + * ; + */ + + var tokenStream = this._tokenStream, + token; + + if (tokenStream.match(Tokens.PERCENTAGE)){ + return SyntaxUnit.fromToken(tokenStream.token()); + } else if (tokenStream.match(Tokens.IDENT)){ + token = tokenStream.token(); + + if (/from|to/i.test(token.value)){ + return SyntaxUnit.fromToken(token); + } + + tokenStream.unget(); + } + + //if it gets here, there wasn't a valid token, so time to explode + this._unexpectedToken(tokenStream.LT(1)); + }, + + //----------------------------------------------------------------- + // Helper methods + //----------------------------------------------------------------- + + /** + * Not part of CSS grammar, but useful for skipping over + * combination of white space and HTML-style comments. + * @return {void} + * @method _skipCruft + * @private + */ + _skipCruft: function(){ + while(this._tokenStream.match([Tokens.S, Tokens.CDO, Tokens.CDC])){ + //noop + } + }, + + /** + * Not part of CSS grammar, but this pattern occurs frequently + * in the official CSS grammar. Split out here to eliminate + * duplicate code. + * @param {Boolean} checkStart Indicates if the rule should check + * for the left brace at the beginning. + * @param {Boolean} readMargins Indicates if the rule should check + * for margin patterns. + * @return {void} + * @method _readDeclarations + * @private + */ + _readDeclarations: function(checkStart, readMargins){ + /* + * Reads the pattern + * S* '{' S* declaration [ ';' S* declaration ]* '}' S* + * or + * S* '{' S* [ declaration | margin ]? [ ';' S* [ declaration | margin ]? ]* '}' S* + * Note that this is how it is described in CSS3 Paged Media, but is actually incorrect. + * A semicolon is only necessary following a delcaration is there's another declaration + * or margin afterwards. + */ + var tokenStream = this._tokenStream, + tt; + + + this._readWhitespace(); + + if (checkStart){ + tokenStream.mustMatch(Tokens.LBRACE); + } + + this._readWhitespace(); + + try { + + while(true){ + + if (tokenStream.match(Tokens.SEMICOLON) || (readMargins && this._margin())){ + //noop + } else if (this._declaration()){ + if (!tokenStream.match(Tokens.SEMICOLON)){ + break; + } + } else { + break; + } + + //if ((!this._margin() && !this._declaration()) || !tokenStream.match(Tokens.SEMICOLON)){ + // break; + //} + this._readWhitespace(); + } + + tokenStream.mustMatch(Tokens.RBRACE); + this._readWhitespace(); + + } catch (ex) { + if (ex instanceof SyntaxError && !this.options.strict){ + + //fire error event + this.fire({ + type: "error", + error: ex, + message: ex.message, + line: ex.line, + col: ex.col + }); + + //see if there's another declaration + tt = tokenStream.advance([Tokens.SEMICOLON, Tokens.RBRACE]); + if (tt == Tokens.SEMICOLON){ + //if there's a semicolon, then there might be another declaration + this._readDeclarations(false, readMargins); + } else if (tt != Tokens.RBRACE){ + //if there's a right brace, the rule is finished so don't do anything + //otherwise, rethrow the error because it wasn't handled properly + throw ex; + } + + } else { + //not a syntax error, rethrow it + throw ex; + } + } + + }, + + /** + * In some cases, you can end up with two white space tokens in a + * row. Instead of making a change in every function that looks for + * white space, this function is used to match as much white space + * as necessary. + * @method _readWhitespace + * @return {String} The white space if found, empty string if not. + * @private + */ + _readWhitespace: function(){ + + var tokenStream = this._tokenStream, + ws = ""; + + while(tokenStream.match(Tokens.S)){ + ws += tokenStream.token().value; + } + + return ws; + }, + + + /** + * Throws an error when an unexpected token is found. + * @param {Object} token The token that was found. + * @method _unexpectedToken + * @return {void} + * @private + */ + _unexpectedToken: function(token){ + throw new SyntaxError("Unexpected token '" + token.value + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); + }, + + /** + * Helper method used for parsing subparts of a style sheet. + * @return {void} + * @method _verifyEnd + * @private + */ + _verifyEnd: function(){ + if (this._tokenStream.LA(1) != Tokens.EOF){ + this._unexpectedToken(this._tokenStream.LT(1)); + } + }, + + //----------------------------------------------------------------- + // Validation methods + //----------------------------------------------------------------- + _validateProperty: function(property, value){ + Validation.validate(property, value); + }, + + //----------------------------------------------------------------- + // Parsing methods + //----------------------------------------------------------------- + + parse: function(input){ + this._tokenStream = new TokenStream(input, Tokens); + this._stylesheet(); + }, + + parseStyleSheet: function(input){ + //just passthrough + return this.parse(input); + }, + + parseMediaQuery: function(input){ + this._tokenStream = new TokenStream(input, Tokens); + var result = this._media_query(); + + //if there's anything more, then it's an invalid selector + this._verifyEnd(); + + //otherwise return result + return result; + }, + + /** + * Parses a property value (everything after the semicolon). + * @return {parserlib.css.PropertyValue} The property value. + * @throws parserlib.util.SyntaxError If an unexpected token is found. + * @method parserPropertyValue + */ + parsePropertyValue: function(input){ + + this._tokenStream = new TokenStream(input, Tokens); + this._readWhitespace(); + + var result = this._expr(); + + //okay to have a trailing white space + this._readWhitespace(); + + //if there's anything more, then it's an invalid selector + this._verifyEnd(); + + //otherwise return result + return result; + }, + + /** + * Parses a complete CSS rule, including selectors and + * properties. + * @param {String} input The text to parser. + * @return {Boolean} True if the parse completed successfully, false if not. + * @method parseRule + */ + parseRule: function(input){ + this._tokenStream = new TokenStream(input, Tokens); + + //skip any leading white space + this._readWhitespace(); + + var result = this._ruleset(); + + //skip any trailing white space + this._readWhitespace(); + + //if there's anything more, then it's an invalid selector + this._verifyEnd(); + + //otherwise return result + return result; + }, + + /** + * Parses a single CSS selector (no comma) + * @param {String} input The text to parse as a CSS selector. + * @return {Selector} An object representing the selector. + * @throws parserlib.util.SyntaxError If an unexpected token is found. + * @method parseSelector + */ + parseSelector: function(input){ + + this._tokenStream = new TokenStream(input, Tokens); + + //skip any leading white space + this._readWhitespace(); + + var result = this._selector(); + + //skip any trailing white space + this._readWhitespace(); + + //if there's anything more, then it's an invalid selector + this._verifyEnd(); + + //otherwise return result + return result; + }, + + /** + * Parses an HTML style attribute: a set of CSS declarations + * separated by semicolons. + * @param {String} input The text to parse as a style attribute + * @return {void} + * @method parseStyleAttribute + */ + parseStyleAttribute: function(input){ + input += "}"; // for error recovery in _readDeclarations() + this._tokenStream = new TokenStream(input, Tokens); + this._readDeclarations(); + } + }; + + //copy over onto prototype + for (prop in additions){ + if (additions.hasOwnProperty(prop)){ + proto[prop] = additions[prop]; + } + } + + return proto; +}(); + + +/* +nth + : S* [ ['-'|'+']? INTEGER? {N} [ S* ['-'|'+'] S* INTEGER ]? | + ['-'|'+']? INTEGER | {O}{D}{D} | {E}{V}{E}{N} ] S* + ; +*/ +/*global Validation, ValidationTypes, ValidationError*/ +var Properties = { + + //A + "alignment-adjust" : "auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical | | ", + "alignment-baseline" : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical", + "animation" : 1, + "animation-delay" : { multi: "