Compare commits

..

45 commits

Author SHA1 Message Date
Fabian Jakobs
cb41085995 add refactor docs 2011-10-04 09:14:26 +02:00
Fabian Jakobs
85ed66edfe fix more unit tests 2011-08-17 14:36:35 +02:00
Fabian Jakobs
968db75cd8 add IE support 2011-08-17 10:27:56 +02:00
Fabian Jakobs
9d14042b37 only call the release capture handler once 2011-08-17 10:26:09 +02:00
Fabian Jakobs
22eb706b42 IE fix for the tokenizer 2011-08-17 10:25:06 +02:00
Fabian Jakobs
62904badce increase threshold for mouse wheel speed limiting 2011-08-17 10:24:41 +02:00
Fabian Jakobs
2f2cddd173 fix demo 2011-08-17 10:15:24 +02:00
Fabian Jakobs
ca4f8fb9b0 take care for excessive scroll speeds in safari 5.0 2011-08-17 09:31:25 +02:00
Fabian Jakobs
c372ec5c9a minor fixes 2011-08-17 09:31:25 +02:00
Fabian Jakobs
1b5c3b29ab move navigation code to the model and update some tests 2011-08-17 09:31:25 +02:00
Fabian Jakobs
3f53212c99 move layer update code into the window model 2011-08-17 09:30:33 +02:00
Fabian Jakobs
0ce6f734d4 move document into the model folder 2011-08-17 09:30:33 +02:00
Fabian Jakobs
f8bab3dbd5 flatten directory hierarchy by removing the
lib directory
2011-08-17 09:27:09 +02:00
Fabian Jakobs
776cf39d12 reorganize js worker code 2011-08-17 09:27:08 +02:00
Fabian Jakobs
133abb1d2d fix merge conflicts 2011-08-17 09:27:08 +02:00
Fabian Jakobs
085ffcf09d small fix 2011-08-17 09:27:07 +02:00
Fabian Jakobs
10b9ad34d5 remove unused code 2011-08-17 09:27:07 +02:00
Fabian Jakobs
606d1bdbaf detect chrome 2011-08-17 09:27:07 +02:00
Fabian Jakobs
6d40f616d5 move search code to the window model 2011-08-17 09:27:07 +02:00
Fabian Jakobs
cd42d284fd move resize handling in the window model 2011-08-17 09:24:42 +02:00
Fabian Jakobs
173d9ce7f7 move buffer listeners from editor.js to the
window controller.
2011-08-17 09:24:11 +02:00
Fabian Jakobs
3cf7ef9a61 no need to pass around the layer config anymore 2011-08-17 09:24:11 +02:00
Fabian Jakobs
82e2920599 don't use layerConfig.{lineHeight,characterHeight}
anymore
2011-08-17 09:23:31 +02:00
Fabian Jakobs
94b434d5e1 package 2011-08-17 09:23:31 +02:00
Fabian Jakobs
801cb923b7 move pilot code back into Ace 2011-08-17 09:21:35 +02:00
Fabian Jakobs
e96918892a computations involving pixels don't belong in the buffer 2011-08-17 09:20:15 +02:00
Fabian Jakobs
86f3fc2a1c move more scrolling code to the window model 2011-08-17 09:20:15 +02:00
Fabian Jakobs
d81d2858ad move more scroll stuff to the model 2011-08-17 09:20:15 +02:00
Fabian Jakobs
3c192c970b remove references to session 2011-08-17 09:20:15 +02:00
Fabian Jakobs
421e19ed78 treat horizontal scrolling just like vertical scrolling 2011-08-17 09:20:15 +02:00
Fabian Jakobs
1018f51b5e move visible row and cursor pixel position
calculation to the window model
2011-08-17 09:20:15 +02:00
Fabian Jakobs
e949f67df2 fix window view mock 2011-08-17 09:20:15 +02:00
Fabian Jakobs
8f8782701b move theme and text size to the window model 2011-08-17 09:19:32 +02:00
Fabian Jakobs
069293b3ff move horizontal scrollbar always visible setting to window model 2011-08-17 09:19:32 +02:00
Fabian Jakobs
1657ffb93e apply MVC to the virtual renderer. Split off all
state into the new WindowModel class and sync using
the new WindowController.
2011-08-17 09:19:32 +02:00
Fabian Jakobs
cca850a8a1 move window view mock into the "view" folder 2011-08-17 09:19:31 +02:00
Fabian Jakobs
a6ab658f15 move ui specific code into the view folder 2011-08-17 09:15:17 +02:00
Fabian Jakobs
0eb476e02f rename virtual_renderer to WindowView 2011-08-16 14:03:15 +02:00
Fabian Jakobs
89eeb3bd1a rename edit session to buffer 2011-08-16 14:01:49 +02:00
Fabian Jakobs
6808e3bb35 I can insert text again 2011-08-16 13:57:38 +02:00
Fabian Jakobs
a58da119b7 get rid of boot.js 2011-08-16 13:57:37 +02:00
Fabian Jakobs
c417dcd4e6 command_manager is no longer a singleton 2011-08-16 13:57:37 +02:00
Fabian Jakobs
8d0e1784e2 remove request argument to commands 2011-08-16 13:57:37 +02:00
Fabian Jakobs
3d011a8827 remove cockpit submodule 2011-08-16 13:57:37 +02:00
Fabian Jakobs
18ab9b4193 remove dependency on canon 2011-08-16 13:57:37 +02:00
1564 changed files with 105875 additions and 308772 deletions

23
.gitignore vendored
View file

@ -2,21 +2,22 @@
.DS_Store .DS_Store
*.swp *.swp
*.tmp *.tmp
*~
# Project files that should not be in the repo # Project files that should not be in the repo
.* .project
\#* .settings/
!/.gitignore .settings.xml
.c9settings.xml
.settings.xml.old
.*.gz .*.gz
*.tmTheme.js
# A handy place to put stuff that git should ignore: # A handy place to put stuff that git should ignore:
/ignore/ /ignore/
node_modules/ support/async/
jam/ support/jsdom/
* * support/node-htmlparser/
support/node-o3-xml/
support/requirejs/
.git-ref /node_modules
npm-debug.log support/node-o3-xml-v4/
deps/

8
.gitmodules vendored
View file

@ -1,6 +1,6 @@
[submodule "support/dryice"]
path = support/dryice
url = git://github.com/ajaxorg/dryice.git
[submodule "doc/wiki"] [submodule "doc/wiki"]
path = doc/wiki path = doc/wiki
url = https://github.com/ajaxorg/ace.wiki.git url = git://github.com/ajaxorg/ace.wiki.git
[submodule "build"]
path = build
url = https://github.com/ajaxorg/ace-builds.git

View file

@ -1 +0,0 @@
language: node_js

1
CNAME
View file

@ -1 +0,0 @@
ace.c9.io

View file

@ -1,15 +0,0 @@
Contributing
------------
Ace is a community project and wouldn't be what it is without contributions! We actively encourage and support contributions. The Ace source code 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!
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:
1. [The Individual CLA](https://docs.google.com/a/c9.io/forms/d/1MfmfrxqD_PNlNsuK0lC2KSelRLxGLGfh_wEcG0ijVvo/viewform): use this version if you're working on the Cloud9 SDK or open source projects in your spare time, or can clearly claim ownership of copyright in what you'll be submitting.
2. [The Corporate CLA](https://docs.google.com/a/c9.io/forms/d/1vFejn4111GdnCNuQ6BfnJDaxdsUEMD4KCo1ayovAfu0/viewform): have your corporate lawyer review and submit this if your company is going to be contributing to the Cloud9 SDK and/or open source projects.
If you want to contribute to the Cloud9 SDK and/or open source projects please go to the online form, fill it out and submit it.
Happy coding, Cloud9

View file

@ -1,229 +1,3 @@
Version 1.2.0-pre
* New Features
- Indented soft wrap (danyaPostfactum)
* API Changes
- unified delta types `{start, end, action, lines}` (Alden Daniels https://github.com/ajaxorg/ace/pull/1745)
- "change" event listeners on session and editor get delta objects directly
2015.04.03 Version 1.1.9
- Small Enhancements and Bugfixes
2014.11.08 Version 1.1.8
* API Changes
- `editor.commands.commandKeyBinding` now contains direct map from keys to commands instead of grouping them by hashid
* New Features
- Improved autoindent for html and php modes (Adam Jimenez)
- Find All from searchbox (Colton Voege)
* new language modes
- Elixir, Elm
2014.09.21 Version 1.1.7
* Bugfixes
- fix several bugs in autocompletion
- workaround for inaccurate getBoundingClientRect on chrome 37
2014.08.17 Version 1.1.6
* Bugfixes
- fix regression in double tap to highlight
- Improved Latex Mode (Daniel Felder)
* API Changes
- editor.destroy destroys editor.session too (call editor.setSession(null) to prevent that)
* new language modes
- Praat (José Joaquín Atria)
- Eiffel (Victorien Elvinger)
- G-code (Adam Joseph Cook)
2014.07.09 Version 1.1.5
* Bugfixes
- fix regression in autocomplete popup
* new language modes
- gitignore (Devon Carew)
2014.07.01 Version 1.1.4
* New Features
- Highlight matching tags (Adam Jimenez)
- Improved jump to matching command (Adam Jimenez)
* new language modes
- AppleScript (Yaogang Lian)
- Vala
2014.03.08 Version 1.1.3
* New Features
- Allow syntax checkers to be loaded from CDN (Derk-Jan Hartman)
- Add ColdFusion behavior (Abram Adams)
- add showLineNumbers option
- Add html syntax checker (danyaPostfactum)
* new language modes
- Gherkin (Patrick Nevels)
- Smarty
2013.12.02 Version 1.1.2
* New Features
- Accessibility Theme for Ace (Peter Xiao)
- use snipetManager for expanding emmet snippets
- update jshint to 2.1.4
- improve php syntax checker (jdalegonzalez)
- add option for autoresizing
- add option for autohiding vertical scrollbar
- improvements to highlighting of xml like languages (danyaPostfactum)
- add support for autocompletion and snippets (gjtorikyan danyaPostfactum and others)
- add option to merge similar changes in undo history
- add scrollPastEnd option
- use html5 dragndrop for text dragging (danyaPostfactum)
* API Changes
- fixed typo in HashHandler commmandManager
* new language modes
- Nix (Zef Hemel)
- Protobuf (Zef Hemel)
- Soy
- Handlebars
2013.06.04 Version 1.1.1
- Improved emacs keybindings (Robert Krahn)
- Added markClean, isClean methods to UndoManager (Joonsoo Jeon)
- Do not allow `Toggle comments` command to remove spaces from indentation
- Softer colors for indent guides in dark themes
* new language modes
- Ada
- Assembly_x86
- Cobol
- D
- ejs
- MATLAB
- MySQL
- Twig
- Verilog
2013.05.01, Version 1.1.0
* API Changes
- Default position of the editor container is changed to relative. Add `.ace_editor {position: absolute}` css rule to restore old behavior
- Changed default line-height to `normal` to not conflict with bootstrap. Use `line-height: inherit` for old behavior.
- Changed marker types accepted by session.addMarker. It now accepts "text"|"line"|"fullLine"|"screenLine"
- Internal classnames used by editor were made more consistent
- Introduced `editor.setOption/getOption/setOptions/getOptions` methods
- Introduced positionToIndex, indexToPosition methods
* New Features
- Improved emacs mode (chetstone)
with Incremental search and Occur modes (Robert Krahn)
- Improved ime handling
- Searchbox (Vlad Zinculescu)
- Added elastic tabstops lite extension (Garen Torikian)
- Added extension for whitespace manipulation
- Added extension for enabling spellchecking from contextmenu
- Added extension for displaying available keyboard shortcuts (Matthew Christopher Kastor-Inare III)
- Added extension for displaying options panel (Matthew Christopher Kastor-Inare III)
- Added modelist extension (Matthew Christopher Kastor-Inare III)
- Improved toggleCommentLines and added ToggleCommentBlock command
- `:;` pairing in CSS mode (danyaPostfactum)
- Added suppoert for Delete and SelectAll from context menu (danyaPostfactum)
- Make wrapping behavior optional
- Selective bracket insertion/skipping
- Added commands for increase/decrease numbers, sort lines (Vlad Zinculescu)
- Folding for Markdown, Lua, LaTeX
- Selective bracket insertion/skipping for C-like languages
* Many new languages
- Scheme (Mu Lei)
- Dot (edwardsp)
- FreeMarker (nguillaumin)
- Tiny Mushcode (h3rb)
- Velocity (Ryan Griffith)
- TOML (Garen Torikian)
- LSL (Nemurimasu Neiro, Builders Brewery)
- Curly (Libo Cannici)
- vbScript (Jan Jongboom)
- R (RStudio)
- ABAP
- Lucene (Graham Scott)
- Haml (Garen Torikian)
- Objective-C (Garen Torikian)
- Makefile (Garen Torikian)
- TypeScript (Garen Torikian)
- Lisp (Garen Torikian)
- Stylus (Garen Torikian)
- Dart (Garen Torikian)
* Live syntax checks
- PHP (danyaPostfactum)
- Lua
* New Themes
- Chaos
- Terminal
2012.09.17, Version 1.0.0
* New Features
- Multiple cursors and selections (https://c9.io/site/blog/2012/08/be-an-armenian-warrior-with-block-selection-on-steroids/)
- Fold buttons displayed in the gutter
- Indent Guides
- Completely reworked vim mode (Sergi Mansilla)
- Improved emacs keybindings
- Autoclosing of html tags (danyaPostfactum)
* 20 New language modes
- Coldfusion (Russ)
- Diff
- GLSL (Ed Mackey)
- Go (Davide Saurino)
- Haxe (Jason O'Neil)
- Jade (Garen Torikian)
- jsx (Syu Kato)
- LaTeX (James Allen)
- Less (John Roepke)
- Liquid (Bernie Telles)
- Lua (Lee Gao)
- LuaPage (Choonster)
- Markdown (Chris Spencer)
- PostgreSQL (John DeSoi)
- Powershell (John Kane)
- Sh (Richo Healey)
- SQL (Jonathan Camile)
- Tcl (Cristoph Hochreiner)
- XQuery (William Candillion)
- Yaml (Meg Sharkey)
* Live syntax checks
- for XQuery and JSON
* New Themes
- Ambiance (Irakli Gozalishvili)
- Dreamweaver (Adam Jimenez)
- Github (bootstraponline)
- Tommorrow themes (https://github.com/chriskempson/tomorrow-theme)
- XCode
* Many Small Enhancements and Bugfixes
2011.08.02, Version 0.2.0 2011.08.02, Version 0.2.0
* Split view (Julian Viereck) * Split view (Julian Viereck)
@ -253,14 +27,15 @@ Version 1.2.0-pre
- SCAD (Jacob Hansson) - SCAD (Jacob Hansson)
* Live syntax checks * Live syntax checks
- Lint for CSS using CSS Lint <http://csslint.net/> - Lint for Css using CSS Lint <http://csslint.net/>
- CoffeeScript - CoffeeScript
* New Themes * New Themes
- Crimson Editor (iebuggy) - Crimson Editor (iebuggy)
- Merbivore (Michael Schwartz) - Merbivore (Michael Schwartz)
- Merbivore soft (Michael Schwartz) - Merbivore soft (Michael Schwartz)
- Solarized dark/light <http://ethanschoonover.com/solarized> (David Alan Hjelle) - Solarized dark/light <http://ethanschoonover.com/solarized> (David Alan
Hjelle)
- Vibrant Ink (Michael Schwartz) - Vibrant Ink (Michael Schwartz)
* Small Features/Enhancements * Small Features/Enhancements
@ -273,8 +48,10 @@ Version 1.2.0-pre
highlight are not affected (Irakli Gozalishvili) highlight are not affected (Irakli Gozalishvili)
- Added setFontSize method - Added setFontSize method
- Improved vi keybindings (Trent Ogren) - Improved vi keybindings (Trent Ogren)
- When unfocused make cursor transparent instead of removing it (Harutyun Amirjanyan) - When unfocused make cursor transparent instead of removing it (Harutyun
- Support for matching groups in tokenizer with arrays of tokens (Chris Spencer) Amirjanyan)
- Support for matching groups in tokenizer with arrays of tokens (Chris
Spencer)
* Bug fixes * Bug fixes
- Add support for the new OSX scroll bars - Add support for the new OSX scroll bars
@ -282,7 +59,8 @@ Version 1.2.0-pre
- Proper handling of unicode characters in JavaScript identifiers - Proper handling of unicode characters in JavaScript identifiers
- Fix remove lines command on last line (Harutyun Amirjanyan) - Fix remove lines command on last line (Harutyun Amirjanyan)
- Fix scroll wheel sluggishness in Safari - Fix scroll wheel sluggishness in Safari
- Make keyboard infrastructure route keys like []^$ the right way (Julian Viereck) - Make keyboard infrastructure route keys like []^$ the right way (Julian
Viereck)
2011.02.14, Version 0.1.6 2011.02.14, Version 0.1.6
@ -335,4 +113,4 @@ Version 1.2.0-pre
* Add Ruby mode contributed by Shlomo Zalman Heigh * Add Ruby mode contributed by Shlomo Zalman Heigh
* Add Java mode contributed by Tom Tasche * Add Java mode contributed by Tom Tasche
* Fix annotation bug * Fix annotation bug
* Changing a document added a new empty line at the end * Changing a document added a new empty line at the end

496
LICENSE
View file

@ -1,24 +1,476 @@
Copyright (c) 2010, Ajax.org B.V. Licensed under the tri-license MPL/LGPL/GPL.
All rights reserved.
Redistribution and use in source and binary forms, with or without MOZILLA PUBLIC LICENSE
modification, are permitted provided that the following conditions are met: Version 1.1
* 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 1. Definitions.
DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 1.0.1. "Commercial Use" means distribution or otherwise making the
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; Covered Code available to a third party.
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.1. "Contributor" means each entity that creates or contributes to
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS the creation of Modifications.
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.2. "Contributor Version" means the combination of the Original
Code, prior Modifications used by a Contributor, and the Modifications
made by that particular Contributor.
1.3. "Covered Code" means the Original Code or Modifications or the
combination of the Original Code and Modifications, in each case
including portions thereof.
1.4. "Electronic Distribution Mechanism" means a mechanism generally
accepted in the software development community for the electronic
transfer of data.
1.5. "Executable" means Covered Code in any form other than Source
Code.
1.6. "Initial Developer" means the individual or entity identified
as the Initial Developer in the Source Code notice required by Exhibit
A.
1.7. "Larger Work" means a work which combines Covered Code or
portions thereof with code not governed by the terms of this License.
1.8. "License" means this document.
1.8.1. "Licensable" means having the right to grant, to the maximum
extent possible, whether at the time of the initial grant or
subsequently acquired, any and all of the rights conveyed herein.
1.9. "Modifications" means any addition to or deletion from the
substance or structure of either the Original Code or any previous
Modifications. When Covered Code is released as a series of files, a
Modification is:
A. Any addition to or deletion from the contents of a file
containing Original Code or previous Modifications.
B. Any new file that contains any part of the Original Code or
previous Modifications.
1.10. "Original Code" means Source Code of computer software code
which is described in the Source Code notice required by Exhibit A as
Original Code, and which, at the time of its release under this
License is not already Covered Code governed by this License.
1.10.1. "Patent Claims" means any patent claim(s), now owned or
hereafter acquired, including without limitation, method, process,
and apparatus claims, in any patent Licensable by grantor.
1.11. "Source Code" means the preferred form of the Covered Code for
making modifications to it, including all modules it contains, plus
any associated interface definition files, scripts used to control
compilation and installation of an Executable, or source code
differential comparisons against either the Original Code or another
well known, available Covered Code of the Contributor's choice. The
Source Code can be in a compressed or archival form, provided the
appropriate decompression or de-archiving software is widely available
for no charge.
1.12. "You" (or "Your") means an individual or a legal entity
exercising rights under, and complying with all of the terms of, this
License or a future version of this License issued under Section 6.1.
For legal entities, "You" includes any entity which controls, is
controlled by, or is under common control with You. For purposes of
this definition, "control" means (a) the power, direct or indirect,
to cause the direction or management of such entity, whether by
contract or otherwise, or (b) ownership of more than fifty percent
(50%) of the outstanding shares or beneficial ownership of such
entity.
2. Source Code License.
2.1. The Initial Developer Grant.
The Initial Developer hereby grants You a world-wide, royalty-free,
non-exclusive license, subject to third party intellectual property
claims:
(a) under intellectual property rights (other than patent or
trademark) Licensable by Initial Developer to use, reproduce,
modify, display, perform, sublicense and distribute the Original
Code (or portions thereof) with or without Modifications, and/or
as part of a Larger Work; and
(b) under Patents Claims infringed by the making, using or
selling of Original Code, to make, have made, use, practice,
sell, and offer for sale, and/or otherwise dispose of the
Original Code (or portions thereof).
(c) the licenses granted in this Section 2.1(a) and (b) are
effective on the date Initial Developer first distributes
Original Code under the terms of this License.
(d) Notwithstanding Section 2.1(b) above, no patent license is
granted: 1) for code that You delete from the Original Code; 2)
separate from the Original Code; or 3) for infringements caused
by: i) the modification of the Original Code or ii) the
combination of the Original Code with other software or devices.
2.2. Contributor Grant.
Subject to third party intellectual property claims, each Contributor
hereby grants You a world-wide, royalty-free, non-exclusive license
(a) under intellectual property rights (other than patent or
trademark) Licensable by Contributor, to use, reproduce, modify,
display, perform, sublicense and distribute the Modifications
created by such Contributor (or portions thereof) either on an
unmodified basis, with other Modifications, as Covered Code
and/or as part of a Larger Work; and
(b) under Patent Claims infringed by the making, using, or
selling of Modifications made by that Contributor either alone
and/or in combination with its Contributor Version (or portions
of such combination), to make, use, sell, offer for sale, have
made, and/or otherwise dispose of: 1) Modifications made by that
Contributor (or portions thereof); and 2) the combination of
Modifications made by that Contributor with its Contributor
Version (or portions of such combination).
(c) the licenses granted in Sections 2.2(a) and 2.2(b) are
effective on the date Contributor first makes Commercial Use of
the Covered Code.
(d) Notwithstanding Section 2.2(b) above, no patent license is
granted: 1) for any code that Contributor has deleted from the
Contributor Version; 2) separate from the Contributor Version;
3) for infringements caused by: i) third party modifications of
Contributor Version or ii) the combination of Modifications made
by that Contributor with other software (except as part of the
Contributor Version) or other devices; or 4) under Patent Claims
infringed by Covered Code in the absence of Modifications made by
that Contributor.
3. Distribution Obligations.
3.1. Application of License.
The Modifications which You create or to which You contribute are
governed by the terms of this License, including without limitation
Section 2.2. The Source Code version of Covered Code may be
distributed only under the terms of this License or a future version
of this License released under Section 6.1, and You must include a
copy of this License with every copy of the Source Code You
distribute. You may not offer or impose any terms on any Source Code
version that alters or restricts the applicable version of this
License or the recipients' rights hereunder. However, You may include
an additional document offering the additional rights described in
Section 3.5.
3.2. Availability of Source Code.
Any Modification which You create or to which You contribute must be
made available in Source Code form under the terms of this License
either on the same media as an Executable version or via an accepted
Electronic Distribution Mechanism to anyone to whom you made an
Executable version available; and if made available via Electronic
Distribution Mechanism, must remain available for at least twelve (12)
months after the date it initially became available, or at least six
(6) months after a subsequent version of that particular Modification
has been made available to such recipients. You are responsible for
ensuring that the Source Code version remains available even if the
Electronic Distribution Mechanism is maintained by a third party.
3.3. Description of Modifications.
You must cause all Covered Code to which You contribute to contain a
file documenting the changes You made to create that Covered Code and
the date of any change. You must include a prominent statement that
the Modification is derived, directly or indirectly, from Original
Code provided by the Initial Developer and including the name of the
Initial Developer in (a) the Source Code, and (b) in any notice in an
Executable version or related documentation in which You describe the
origin or ownership of the Covered Code.
3.4. Intellectual Property Matters
(a) Third Party Claims.
If Contributor has knowledge that a license under a third party's
intellectual property rights is required to exercise the rights
granted by such Contributor under Sections 2.1 or 2.2,
Contributor must include a text file with the Source Code
distribution titled "LEGAL" which describes the claim and the
party making the claim in sufficient detail that a recipient will
know whom to contact. If Contributor obtains such knowledge after
the Modification is made available as described in Section 3.2,
Contributor shall promptly modify the LEGAL file in all copies
Contributor makes available thereafter and shall take other steps
(such as notifying appropriate mailing lists or newsgroups)
reasonably calculated to inform those who received the Covered
Code that new knowledge has been obtained.
(b) Contributor APIs.
If Contributor's Modifications include an application programming
interface and Contributor has knowledge of patent licenses which
are reasonably necessary to implement that API, Contributor must
also include this information in the LEGAL file.
(c) Representations.
Contributor represents that, except as disclosed pursuant to
Section 3.4(a) above, Contributor believes that Contributor's
Modifications are Contributor's original creation(s) and/or
Contributor has sufficient rights to grant the rights conveyed by
this License.
3.5. Required Notices.
You must duplicate the notice in Exhibit A in each file of the Source
Code. If it is not possible to put such notice in a particular Source
Code file due to its structure, then You must include such notice in a
location (such as a relevant directory) where a user would be likely
to look for such a notice. If You created one or more Modification(s)
You may add your name as a Contributor to the notice described in
Exhibit A. You must also duplicate this License in any documentation
for the Source Code where You describe recipients' rights or ownership
rights relating to Covered Code. You may choose to offer, and to
charge a fee for, warranty, support, indemnity or liability
obligations to one or more recipients of Covered Code. However, You
may do so only on Your own behalf, and not on behalf of the Initial
Developer or any Contributor. You must make it absolutely clear than
any such warranty, support, indemnity or liability obligation is
offered by You alone, and You hereby agree to indemnify the Initial
Developer and every Contributor for any liability incurred by the
Initial Developer or such Contributor as a result of warranty,
support, indemnity or liability terms You offer.
3.6. Distribution of Executable Versions.
You may distribute Covered Code in Executable form only if the
requirements of Section 3.1-3.5 have been met for that Covered Code,
and if You include a notice stating that the Source Code version of
the Covered Code is available under the terms of this License,
including a description of how and where You have fulfilled the
obligations of Section 3.2. The notice must be conspicuously included
in any notice in an Executable version, related documentation or
collateral in which You describe recipients' rights relating to the
Covered Code. You may distribute the Executable version of Covered
Code or ownership rights under a license of Your choice, which may
contain terms different from this License, provided that You are in
compliance with the terms of this License and that the license for the
Executable version does not attempt to limit or alter the recipient's
rights in the Source Code version from the rights set forth in this
License. If You distribute the Executable version under a different
license You must make it absolutely clear that any terms which differ
from this License are offered by You alone, not by the Initial
Developer or any Contributor. You hereby agree to indemnify the
Initial Developer and every Contributor for any liability incurred by
the Initial Developer or such Contributor as a result of any such
terms You offer.
3.7. Larger Works.
You may create a Larger Work by combining Covered Code with other code
not governed by the terms of this License and distribute the Larger
Work as a single product. In such a case, You must make sure the
requirements of this License are fulfilled for the Covered Code.
4. Inability to Comply Due to Statute or Regulation.
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Code due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description
must be included in the LEGAL file described in Section 3.4 and must
be included with all distributions of the Source Code. Except to the
extent prohibited by statute or regulation, such description must be
sufficiently detailed for a recipient of ordinary skill to be able to
understand it.
5. Application of this License.
This License applies to code to which the Initial Developer has
attached the notice in Exhibit A and to related Covered Code.
6. Versions of the License.
6.1. New Versions.
Netscape Communications Corporation ("Netscape") may publish revised
and/or new versions of the License from time to time. Each version
will be given a distinguishing version number.
6.2. Effect of New Versions.
Once Covered Code has been published under a particular version of the
License, You may always continue to use it under the terms of that
version. You may also choose to use such Covered Code under the terms
of any subsequent version of the License published by Netscape. No one
other than Netscape has the right to modify the terms applicable to
Covered Code created under this License.
6.3. Derivative Works.
If You create or use a modified version of this License (which you may
only do in order to apply it to code which is not already Covered Code
governed by this License), You must (a) rename Your license so that
the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
"MPL", "NPL" or any confusingly similar phrase do not appear in your
license (except to note that your license differs from this License)
and (b) otherwise make it clear that Your version of the license
contains terms which differ from the Mozilla Public License and
Netscape Public License. (Filling in the name of the Initial
Developer, Original Code or Contributor in the notice described in
Exhibit A shall not of themselves be deemed to be modifications of
this License.)
7. DISCLAIMER OF WARRANTY.
COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
8. TERMINATION.
8.1. This License and the rights granted hereunder will terminate
automatically if You fail to comply with terms herein and fail to cure
such breach within 30 days of becoming aware of the breach. All
sublicenses to the Covered Code which are properly granted shall
survive any termination of this License. Provisions which, by their
nature, must remain in effect beyond the termination of this License
shall survive.
8.2. If You initiate litigation by asserting a patent infringement
claim (excluding declatory judgment actions) against Initial Developer
or a Contributor (the Initial Developer or Contributor against whom
You file such action is referred to as "Participant") alleging that:
(a) such Participant's Contributor Version directly or indirectly
infringes any patent, then any and all rights granted by such
Participant to You under Sections 2.1 and/or 2.2 of this License
shall, upon 60 days notice from Participant terminate prospectively,
unless if within 60 days after receipt of notice You either: (i)
agree in writing to pay Participant a mutually agreeable reasonable
royalty for Your past and future use of Modifications made by such
Participant, or (ii) withdraw Your litigation claim with respect to
the Contributor Version against such Participant. If within 60 days
of notice, a reasonable royalty and payment arrangement are not
mutually agreed upon in writing by the parties or the litigation claim
is not withdrawn, the rights granted by Participant to You under
Sections 2.1 and/or 2.2 automatically terminate at the expiration of
the 60 day notice period specified above.
(b) any software, hardware, or device, other than such Participant's
Contributor Version, directly or indirectly infringes any patent, then
any rights granted to You by such Participant under Sections 2.1(b)
and 2.2(b) are revoked effective as of the date You first made, used,
sold, distributed, or had made, Modifications made by that
Participant.
8.3. If You assert a patent infringement claim against Participant
alleging that such Participant's Contributor Version directly or
indirectly infringes any patent where such claim is resolved (such as
by license or settlement) prior to the initiation of patent
infringement litigation, then the reasonable value of the licenses
granted by such Participant under Sections 2.1 or 2.2 shall be taken
into account in determining the amount or value of any payment or
license.
8.4. In the event of termination under Sections 8.1 or 8.2 above,
all end user license agreements (excluding distributors and resellers)
which have been validly granted by You or any distributor hereunder
prior to termination shall survive termination.
9. LIMITATION OF LIABILITY.
UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
(INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
10. U.S. GOVERNMENT END USERS.
The Covered Code is a "commercial item," as that term is defined in
48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
software" and "commercial computer software documentation," as such
terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
all U.S. Government End Users acquire Covered Code with only those
rights set forth herein.
11. MISCELLANEOUS.
This License represents the complete agreement concerning subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. This License shall be governed by
California law provisions (except to the extent applicable law, if
any, provides otherwise), excluding its conflict-of-law provisions.
With respect to disputes in which at least one party is a citizen of,
or an entity chartered or registered to do business in the United
States of America, any litigation relating to this License shall be
subject to the jurisdiction of the Federal Courts of the Northern
District of California, with venue lying in Santa Clara County,
California, with the losing party responsible for costs, including
without limitation, court costs and reasonable attorneys' fees and
expenses. The application of the United Nations Convention on
Contracts for the International Sale of Goods is expressly excluded.
Any law or regulation which provides that the language of a contract
shall be construed against the drafter shall not apply to this
License.
12. RESPONSIBILITY FOR CLAIMS.
As between Initial Developer and the Contributors, each party is
responsible for claims and damages arising, directly or indirectly,
out of its utilization of rights under this License and You agree to
work with Initial Developer and Contributors to distribute such
responsibility on an equitable basis. Nothing herein is intended or
shall be deemed to constitute any admission of liability.
13. MULTIPLE-LICENSED CODE.
Initial Developer may designate portions of the Covered Code as
"Multiple-Licensed". "Multiple-Licensed" means that the Initial
Developer permits you to utilize portions of the Covered Code under
Your choice of the NPL or the alternative licenses, if any, specified
by the Initial Developer in the file described in Exhibit A.
EXHIBIT A -Mozilla Public License.
``The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific language governing rights and limitations
under the License.
The Original Code is ______________________________________.
The Initial Developer of the Original Code is ________________________.
Portions created by ______________________ are Copyright (C) ______
_______________________. All Rights Reserved.
Contributor(s): ______________________________________.
Alternatively, the contents of this file may be used under the terms
of the _____ license (the "[___] License"), in which case the
provisions of [______] License are applicable instead of those
above. If you wish to allow use of your version of this file only
under the terms of the [____] License and not to allow others to use
your version of this file under the MPL, indicate your decision by
deleting the provisions above and replace them with the notice and
other provisions required by the [___] License. If you do not delete
the provisions above, a recipient may use your version of this file
under either the MPL or the [___] License."
[NOTE: The text of this Exhibit A may differ slightly from the text of
the notices in the Source Code files of the Original Code. You should
use the text of this Exhibit A rather than the text found in the
Original Code Source Code for Your Modifications.]
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007

View file

@ -1,34 +1,13 @@
.PHONY : doc build clean dist build:
pre_build:
git rev-parse HEAD > .git-ref
mkdir -p build/src mkdir -p build/src
mkdir -p build/demo/kitchen-sink mkdir -p build/demo
mkdir -p build/textarea/src mkdir -p build/textarea/src
cp -r demo/kitchen-sink/styles.css build/demo/kitchen-sink/styles.css cp demo/styles.css build/demo/styles.css
cp demo/kitchen-sink/logo.png build/demo/kitchen-sink/logo.png cp demo/logo.png build/demo/logo.png
cp -r doc/site/images build/textarea
build: pre_build
./Makefile.dryice.js normal ./Makefile.dryice.js normal
./Makefile.dryice.js demo ./Makefile.dryice.js bm
# Minimal build: call Makefile.dryice.js only if our sources changed
basic: build/src/ace.js
build/src/ace.js : ${wildcard lib/*} \
${wildcard lib/*/*} \
${wildcard lib/*/*/*} \
${wildcard lib/*/*/*/*} \
${wildcard lib/*/*/*/*/*} \
${wildcard lib/*/*/*/*/*/*}
./Makefile.dryice.js
doc:
cd doc;\
(test -d node_modules && npm update) || npm install;\
node build.js
clean: clean:
rm -rf build rm -rf build

View file

@ -1,571 +1,367 @@
#!/usr/bin/env node #!/usr/bin/env node
/* ***** BEGIN LICENSE BLOCK ***** /* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
* *
* Copyright (c) 2010, Ajax.org B.V. * The contents of this file are subject to the Mozilla Public License Version
* All rights reserved. * 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
* *
* Redistribution and use in source and binary forms, with or without * Software distributed under the License is distributed on an "AS IS" basis,
* modification, are permitted provided that the following conditions are met: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* * Redistributions of source code must retain the above copyright * for the specific language governing rights and limitations under the
* notice, this list of conditions and the following disclaimer. * License.
* * 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 * The Original Code is Ajax.org Code Editor (ACE).
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * The Initial Developer of the Original Code is
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY * Ajax.org B.V.
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * Portions created by the Initial Developer are Copyright (C) 2010
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * the Initial Developer. All Rights Reserved.
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * Contributor(s):
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * Fabian Jakobs <fabian AT ajax DOT org>
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * Julian Viereck <julian.viereck@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
* *
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
var fs = require("fs"); var args = process.argv;
var path = require("path"); var target = null;
var copy = require('architect-build/copy'); var targetDir = null;
var build = require('architect-build/build'); if (args.length == 3) {
target = args[2];
var ACE_HOME = __dirname; // Check if 'target' contains some allowed value.
var BUILD_DIR = ACE_HOME + "/build"; if (target != "normal" && target != "bm") {
var CACHE = {}; target = null;
function main(args) {
if (args.indexOf("updateModes") !== -1) {
return updateModes();
} }
var type = "minimal"; }
args = args.map(function(x) {
if (x[0] == "-" && x[1] != "-")
return "-" + x;
return x;
}).filter(Boolean);
if (args[2] && (args[2][0] != "-" || args[2].indexOf("h") != -1)) if (!target) {
type = args[2]; console.log("--- Ace Dryice Build Tool ---");
console.log("");
console.log("Options:");
console.log(" normal Runs embedded build of Ace");
console.log(" bm Runs bookmarklet build of Ace");
process.exit(0);
} else {
if (target == "normal") {
targetDir = "build";
} else {
targetDir = "build/textarea";
function shadow(input) {
if (typeof input !== 'string') {
input = input.toString();
}
var i = args.indexOf("--target"); return input.replace(/define\(/g, "__ace_shadowed__.define(");
if (i != -1 && args[i+1])
BUILD_DIR = args[i+1];
if (args.indexOf("--h") == -1) {
if (type == "minimal") {
buildAce({
compress: args.indexOf("--m") != -1,
noconflict: args.indexOf("--nc") != -1,
shrinkwrap: args.indexOf("--s") != -1
});
} else if (type == "normal") {
ace();
} else if (type == "demo") {
demo();
} else if (type == "full") {
ace();
demo();
} else if (type == "highlighter") {
// TODO
} }
} }
} }
function showHelp(type) { console.log("using targetDir '", targetDir, "'");
console.log("--- Ace Dryice Build Tool ---");
console.log("");
console.log("Options:");
console.log(" minimal Places necessary Ace files out in build dir; uses configuration flags below [default]");
console.log(" normal Runs four Ace builds--minimal, minimal-noconflict, minimal-min, and minimal-noconflict-min");
console.log(" demo Runs demo build of Ace");
console.log(" full all of above");
console.log(" highlighter ");
console.log("args:");
console.log(" --target ./path path to build folder");
console.log("flags:");
console.log(" --h print this help");
console.log(" --m minify");
console.log(" --nc namespace require");
console.log(" --s shrinkwrap (combines all output files into one)");
console.log("");
if (type)
console.log(" output for " + type + " generated in " + BUILD_DIR);
}
function ace() { var copy = require('./support/dryice/lib/dryice').copy;
console.log('# ace License | Readme | Changelog ---------');
copy.file(ACE_HOME + "/build_support/editor.html", BUILD_DIR + "/editor.html"); var aceHome = __dirname;
copy.file(ACE_HOME + "/LICENSE", BUILD_DIR + "/LICENSE");
copy.file(ACE_HOME + "/ChangeLog.txt", BUILD_DIR + "/ChangeLog.txt"); console.log('# ace ---------');
var aceProject = [
aceHome
];
if (target == "normal") {
aceProject.push(aceHome + '/demo');
copy({
source: "build_support/editor.html",
dest: targetDir + '/editor.html'
});
console.log('# ace ---------'); demo();
for (var i = 0; i < 4; i++) } else if(target == "bm") {
buildAce({compress: i & 2, noconflict: i & 1}); copy({
source: "build_support/editor_textarea.html",
dest: targetDir + '/editor.html'
});
copy({
source: "build_support/style.css",
dest: targetDir + '/style.css'
});
} }
var project = copy.createCommonJsProject(aceProject);
function filterTextPlugin(text) {
return text.replace(/(['"])text\!/g, "$1text/");
/*return text
.replace(/define\(\s*['"]text\!\)/g, "text/")
.replace(/require\(\s*['"]text\!\)/g, "text/")*/
}
var ace = copy.createDataObject();
copy({
source: [
target == "normal"
? 'build_support/mini_require.js'
: 'build_support/mini_require_textarea.js'
],
dest: ace
});
copy({
source: [
copy.source.commonjs({
project: project,
require: ["ace/ace"]
})
],
filter: [ copy.filter.moduleDefines ],
dest: ace
});
copy({
source: {
root: project,
include: /.*\.css$/,
exclude: /tests?\//
},
filter: [ copy.filter.addDefines ],
dest: ace
});
copy({
source: [
target == "normal"
? 'build_support/boot.js'
: 'build_support/boot_textarea.js'
],
dest: ace
});
if (target == "normal") {
// Create the compressed and uncompressed output files
copy({
source: ace,
filter: [copy.filter.uglifyjs, filterTextPlugin],
dest: targetDir + '/src/ace.js'
});
copy({
source: ace,
filter: [filterTextPlugin],
dest: targetDir + '/src/ace-uncompressed.js'
});
} else if (target == "bm") {
copy({
source: ace,
filter: [
shadow,
copy.filter.uglifyjs
],
dest: targetDir + '/src/ace.js'
});
copy({
source: ace,
filter: [
shadow
],
dest: targetDir + '/src/ace-uncompressed.js'
});
}
var modeThemeFilters;
if (target == "normal") {
modeThemeFilters = [
copy.filter.moduleDefines,
copy.filter.uglifyjs,
filterTextPlugin
];
} else if (target == "bm") {
modeThemeFilters = [
copy.filter.moduleDefines,
shadow,
copy.filter.uglifyjs
]
}
console.log('# ace modes ---------');
project.assumeAllFilesLoaded();
[
"css", "html", "javascript", "php", "python", "xml", "ruby", "java", "c_cpp",
"coffee", "perl", "csharp", "svg", "clojure", "scss", "json", "groovy",
"ocaml", "scala", "textile", "scad"
].forEach(function(mode) {
console.log("mode " + mode);
copy({
source: [
copy.source.commonjs({
project: project.clone(),
require: [ 'ace/mode/' + mode ]
})
],
filter: modeThemeFilters,
dest: targetDir + "/src/mode-" + mode + ".js"
});
});
console.log('# ace themes ---------');
[
"clouds", "clouds_midnight", "cobalt", "crimson_editor", "dawn", "eclipse",
"idle_fingers", "kr_theme", "merbivore", "merbivore_soft",
"mono_industrial", "monokai", "pastel_on_dark", "solarized_dark",
"solarized_light", "textmate", "twilight", "vibrant_ink"
].forEach(function(theme) {
copy({
source: [{
root: aceHome,
include: "ace/theme/" + theme + ".js"
}],
filter: modeThemeFilters,
dest: targetDir + "/src/theme-" + theme + ".js"
});
});
console.log('# ace License | Readme | Changelog ---------');
copy({
source: aceHome + "/LICENSE",
dest: targetDir + '/LICENSE'
});
copy({
source: aceHome + "/Readme.md",
dest: targetDir + '/Readme.md'
});
copy({
source: aceHome + "/ChangeLog.txt",
dest: targetDir + '/ChangeLog.txt'
});
// For the bookmarklet build, we are done.
if (target == "bm") {
process.exit(0);
}
console.log('# ace worker ---------');
["javascript", "coffee", "css"].forEach(function(mode) {
console.log("worker for " + mode + " mode");
var worker = copy.createDataObject();
var workerProject = copy.createCommonJsProject([
aceHome
]);
copy({
source: [
copy.source.commonjs({
project: workerProject,
require: [
'ace/lib/fixoldbrowsers',
'ace/lib/event_emitter',
'ace/lib/oop',
'ace/mode/' + mode + '_worker'
]
})
],
filter: [ copy.filter.moduleDefines],
dest: worker
});
copy({
source: [
aceHome + "/ace/worker/worker.js",
worker
],
filter: [ copy.filter.uglifyjs, filterTextPlugin ],
dest: "build/src/worker-" + mode + ".js"
});
});
console.log('# ace key bindings ---------');
// copy key bindings
project.assumeAllFilesLoaded();
["vim", "emacs"].forEach(function(keybinding) {
copy({
source: [
copy.source.commonjs({
project: project.clone(),
require: [ 'ace/keyboard/keybinding/' + keybinding ]
})
],
filter: [ copy.filter.moduleDefines, copy.filter.uglifyjs, filterTextPlugin ],
dest: "build/src/keybinding-" + keybinding + ".js"
});
});
function demo() { function demo() {
console.log('# kitchen sink ---------'); console.log('# kitchen sink ---------');
var version = "", ref = ""; copy({
try { source: "kitchen-sink.html",
version = JSON.parse(fs.readFileSync(ACE_HOME + "/package.json")).version; dest: "build/kitchen-sink.html",
ref = fs.readFileSync(ACE_HOME + "/.git-ref").toString(); filter: [ function(data) {
} catch(e) {} return (data
.replace("DEVEL-->", "")
function changeComments(data) { .replace("<!--DEVEL", "")
return (data .replace("PACKAGE-->", "")
.replace("doc/site/images/ace-logo.png", "demo/kitchen-sink/ace-logo.png") .replace("<!--PACKAGE", ""));
.replace(/<!\-\-DEVEL[\d\D]*?DEVEL\-\->/g, "") }]
.replace(/PACKAGE\-\->|<!\-\-PACKAGE/g, "")
.replace(/\/\*DEVEL[\d\D]*?DEVEL\*\//g, "")
.replace(/PACKAGE\*\/|\/\*PACKAGE/g, "")
.replace("%version%", version)
.replace("%commit%", ref)
);
}
copy(ACE_HOME +"/demo/kitchen-sink/docs/", BUILD_DIR + "/demo/kitchen-sink/docs/");
copy.file(ACE_HOME + "/demo/kitchen-sink/logo.png", BUILD_DIR + "/demo/kitchen-sink/logo.png");
copy.file(ACE_HOME + "/demo/kitchen-sink/styles.css", BUILD_DIR + "/demo/kitchen-sink/styles.css");
copy.file(ACE_HOME + "/kitchen-sink.html", BUILD_DIR + "/kitchen-sink.html", changeComments);
buildSubmodule({}, {
require: ["kitchen-sink/demo"],
projectType: "demo"
}, BUILD_DIR + "/demo/kitchen-sink/demo");
copy(ACE_HOME + "/demo/", BUILD_DIR + "/demo/", {
shallow: true,
exclude: /\s|requirejs/,
include: /\.(js|html)$/,
replace: function(source) {
if (!/^\s*</.test(source))
return source;
var removeRequireJS;
source = source.replace(/<script src="kitchen-sink\/require.js"[\s\S]+?require\(\[([^\]]+).*/, function(e, m) {
removeRequireJS = true;
var scripts = m.split(/,\s*/);
var result = [];
function comment(str) {result.push("<!-- " + str + " -->")}
function script(str) {result.push('<script src="../src/' + str + '.js"></script>')}
scripts.forEach(function(s) {
s = s.replace(/"/g, "");
if (s == "ace/ace") {
comment("load ace");
script("ace");
} else {
var extName = s.match(/[^/]*$/)[0];
comment("load ace " + extName + " extension");
script("ext-" + extName);
}
});
result.push("<script>");
return result.join("\n");
});
if (removeRequireJS)
source = source.replace(/\s*\}\);?\s*(<\/script>)/, "\n$1");
source = source.replace(/"\.\.\/build\//g, function(e) {
console.log(e); return '"../';
});
return source;
}
}); });
}
function jsFileList(path, filter) { var project = copy.createCommonJsProject(aceProject);
path = ACE_HOME + "/" + path; var demo = copy.createDataObject();
if (!filter) copy({
filter = /_test/; source: [
'build_support/mini_require.js'
return fs.readdirSync(path).map(function(x) { ],
if (x.slice(-3) == ".js" && !filter.test(x) && !/\s|BASE|(\b|_)dummy(\b|_)/.test(x)) dest: demo
return x.slice(0, -3); });
}).filter(Boolean); copy({
} source: [
copy.source.commonjs({
function workers(path) { project: project,
return jsFileList(path).map(function(x) { require: [ "demo/demo" ]
if (x.slice(-7) == "_worker") })
return x.slice(0, -7); ],
}).filter(function(x) { return !!x; }); filter: [ copy.filter.moduleDefines ],
} dest: demo
});
function modeList() { copy({
return jsFileList("lib/ace/mode", /_highlight_rules|_test|_worker|xml_util|_outdent|behaviour|completions/); source: {
} root: project,
include: /demo\/docs\/.*$/,
function buildAceModule(opts, callback) { exclude: /tests?\//
// calling buildAceModuleInternal many times in parallel is slow, so we use queue
if (!buildAceModule.queue) {
buildAceModule.queue = [];
buildAceModule.dequeue = function() {
if (buildAceModule.running) return;
var call = buildAceModule.queue.shift();
buildAceModule.running = call;
if (call)
buildAceModuleInternal.apply(null, call);
};
}
buildAceModule.queue.push([opts, function(err, result) {
callback && callback(err, result);
buildAceModule.running = null;
buildAceModule.dequeue();
}]);
if (!buildAceModule.running) {
buildAceModule.dequeue();
} else {
process.nextTick(buildAceModule.dequeue);
}
}
function buildAceModuleInternal(opts, callback) {
var cache = opts.cache == undefined ? CACHE : opts.cache;
var key = opts.require + "|" + opts.projectType;
if (cache && cache.configs && cache.configs[key])
return write(null, cache.configs[key]);
var pathConfig = {
paths: {
ace: ACE_HOME + "/lib/ace",
"kitchen-sink": ACE_HOME + "/demo/kitchen-sink",
build_support: ACE_HOME + "/build_support",
}, },
root: ACE_HOME filter: [ copy.filter.addDefines ],
}; dest: demo
});
function write(err, result) { copy({
if (cache && key && !(cache.configs && cache.configs[key])) { source: {
cache.configs = cache.configs || Object.create(null); root: project,
cache.configs[key] = result; include: /.*\.css$/,
result.sources = result.sources.map(function(pkg) { exclude: /tests?\//
return {deps: pkg.deps}; },
}); filter: [ copy.filter.addDefines ],
} dest: demo
});
if (!opts.outputFile)
return callback(err, result);
var code = result.code;
if (opts.compress) {
if (!result.codeMin)
result.codeMin = compress(result.code);
code = result.codeMin;
}
var targetDir = BUILD_DIR + "/src";
if (opts.compress)
targetDir += "-min";
if (opts.noconflict)
targetDir += "-noconflict";
var to = /^([\\/]|\w:)/.test(opts.outputFile)
? opts.outputFile
: path.join(opts.outputFolder || targetDir, opts.outputFile);
var filters = [];
var ns = opts.ns || "ace"; copy({
if (opts.filters) source: demo,
filters = filters.concat(opts.filters); filter: copy.filter.uglifyjs,
dest: 'build/demo/kitchen-sink.js'
if (opts.noconflict) });
filters.push(namespace(ns)); copy({
var projectType = opts.projectType; source: demo,
if (projectType == "main" || projectType == "ext") { dest: 'build/demo/kitchen-sink-uncompressed.js'
filters.push(exportAce(ns, opts.require[0],
opts.noconflict ? ns : "", projectType == "ext"));
}
filters.forEach(function(f) { code = f(code); });
build.writeToFile({code: code}, {
outputFolder: path.dirname(to),
outputFile: path.basename(to),
}, function() {});
callback && callback(err, result);
}
build(opts.require, {
cache: cache,
quiet: opts.quiet,
pathConfig: pathConfig,
additional: opts.additional,
enableBrowser: true,
keepDepArrays: "all",
noArchitect: true,
compress: false,
ignore: opts.ignore || [],
withRequire: false,
basepath: ACE_HOME,
transforms: [normalizeLineEndings],
afterRead: [optimizeTextModules]
}, write);
}
function buildCore(options, extra, callback) {
options = extend(extra, options);
options.additional = [{
id: "build_support/mini_require",
order: -1000,
literal: true
}];
options.require =["ace/ace"];
options.projectType = "main";
options.ns = "ace";
buildAceModule(options, callback);
}
function buildSubmodule(options, extra, file, callback) {
options = extend(extra, options);
getLoadedFileList(options, function(coreFiles) {
options.outputFile = file + ".js";
options.ignore = options.ignore || coreFiles;
options.quiet = true;
buildAceModule(options, callback);
}); });
} }
function buildAce(options) {
var snippetFiles = jsFileList("lib/ace/snippets");
var modeNames = modeList();
buildCore(options, {outputFile: "ace.js"}),
// modes
modeNames.forEach(function(name) {
buildSubmodule(options, {
projectType: "mode",
require: ["ace/mode/" + name]
}, "mode-" + name);
});
// snippets
modeNames.forEach(function(name) {
if (snippetFiles.indexOf(name + ".js") == -1)
addSnippetFile(name);
buildSubmodule(options, {
require: ["ace/snippets/" + name],
}, "snippets/" + name);
});
// themes
jsFileList("lib/ace/theme").forEach(function(name) {
buildSubmodule(options, {
projectType: "theme",
require: ["ace/theme/" + name]
}, "theme-" + name);
});
// keybindings
["vim", "emacs"].forEach(function(name) {
buildSubmodule(options, {
projectType: "keybinding",
require: ["ace/keyboard/" + name ]
}, "keybinding-" + name);
});
// extensions
jsFileList("lib/ace/ext").forEach(function(name) {
buildSubmodule(options, {
projectType: "ext",
require: ["ace/ext/" + name]
}, "ext-" + name);
});
// workers
workers("lib/ace/mode").forEach(function(name) {
buildSubmodule(options, {
projectType: "worker",
require: ["ace/mode/" + name + "_worker"],
ignore: [],
additional: [{
id: "ace/worker/worker",
transforms: [],
order: -1000
}],
}, "worker-" + name);
});
}
function getLoadedFileList(options, callback, result) {
if (!result) {
return buildCore({}, {}, function(e, result) {
getLoadedFileList(options, callback, result);
});
}
var deps = Object.create(null);
result.sources.forEach(function(pkg) {
pkg.deps && pkg.deps.forEach(function(p) {
if (!deps[p]) deps[p] = 1;
});
});
delete deps["ace/theme/textmate"];
callback(Object.keys(deps));
}
function normalizeLineEndings(module) {
module.source = module.source.replace(/\r\n/g, "\n");
}
function optimizeTextModules(sources) {
var textModules = {};
return sources.filter(function(pkg) {
if (!pkg.id) {
return true;
}
else if (pkg.id.indexOf("text!") > -1) {
detectTextModules(pkg);
return false;
}
else {
pkg.source = rewriteTextImports(pkg.source, pkg.deps);
return true;
}
}).map(function(pkg) {
if (pkg && pkg.deps) {
pkg.deps = pkg.deps && pkg.deps.filter(function(p) {
return p.indexOf("text!") == -1;
});
}
return pkg;
});
function rewriteTextImports(text, deps) {
return text.replace(/ require\(['"](?:ace|[.\/]+)\/requirejs\/text!(.*?)['"]\)/g, function(_, call) {
if (call) {
var dep;
deps.some(function(d) {
if (d.split("/").pop() == call.split("/").pop()) {
dep = d;
return true;
}
});
call = textModules[dep];
if (call)
return " " + call;
}
});
}
function detectTextModules(pkg) {
var input = pkg.source.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
if (/\.css$/.test(pkg.id)) {
// remove unnecessary whitespace from css
input = input.replace(/\n\s+/g, "\n");
input = '"' + input.replace(/\n/g, '\\\n') + '"';
} else {
// but don't break other files!
input = '"' + input.replace(/\n/g, '\\n\\\n') + '"';
}
textModules[pkg.id] = input;
}
}
function namespace(ns) {
return function(text) {
text = text
.toString()
.replace(/ACE_NAMESPACE\s*=\s*""/, 'ACE_NAMESPACE = "' + ns +'"')
.replace(/(\.define)|\bdefine\(/g, function(_, a) {
return a || ns + ".define(";
});
return text;
};
}
function exportAce(ns, modules, requireBase, extModules) {
requireBase = requireBase || "window";
return function(text) {
/*globals REQUIRE_NS, MODULES, NS*/
var template = function() {
(function() {
REQUIRE_NS.require(MODULES, function(a) {
a && a.config.init(true);
if (!window.NS)
window.NS = a;
for (var key in a) if (a.hasOwnProperty(key))
window.NS[key] = a[key];
});
})();
};
if (extModules) {
template = function() {
(function() {
REQUIRE_NS.require(MODULES, function() {});
})();
};
}
text = text.replace(/function init\(packaged\) {/, "init(true);$&\n");
if (typeof modules == "string")
modules = [modules];
return (text.replace(/;\s*$/, "") + ";" + template
.toString()
.replace(/MODULES/g, JSON.stringify(modules))
.replace(/REQUIRE_NS/g, requireBase)
.replace(/NS/g, ns)
.slice(13, -1)
);
};
}
function updateModes() {
modeList().forEach(function(m) {
var filepath = __dirname + "/lib/ace/mode/" + m + ".js";
var source = fs.readFileSync(filepath, "utf8");
if (!/this.\$id\s*=\s*"/.test(source))
source = source.replace(/\n([ \t]*)(\}\).call\(\w*Mode.prototype\))/, '\n$1 this.$id = "";\n$1$2');
source = source.replace(/(this.\$id\s*=\s*)"[^"]*"/, '$1"ace/mode/' + m + '"');
fs.writeFileSync(filepath, source, "utf8");
});
}
function generateThemesModule(themes) {
var themelist = [
'define(function(require, exports, module) {',
'\n\nmodule.exports.themes = ' + JSON.stringify(themes, null, ' '),
';\n\n});'
].join('');
fs.writeFileSync(__dirname + '/lib/ace/ext/themelist_utils/themes.js', themelist, 'utf8');
}
function addSnippetFile(modeName) {
var snippetFilePath = ACE_HOME + "/lib/ace/snippets/" + modeName;
if (!fs.existsSync(snippetFilePath + ".js")) {
copy.file(ACE_HOME + "/tool/templates/snippets.js", snippetFilePath + ".js", function(t) {
return t.replace(/%modeName%/g, modeName);
});
}
if (!fs.existsSync(snippetFilePath + ".snippets")) {
fs.writeFileSync(snippetFilePath + ".snippets", "");
}
}
function compress(text) {
var ujs = require("dryice").copy.filter.uglifyjs;
ujs.options.mangle_toplevel = {except: ["ACE_NAMESPACE", "requirejs"]};
ujs.options.beautify = {ascii_only: true, inline_script: true}
return ujs(text);
}
function extend(base, extra) {
Object.keys(extra).forEach(function(k) {
base[k] = extra[k];
});
return base;
}
if (!module.parent)
main(process.argv);
else
exports.buildAce = buildAce;

131
Readme.md
View file

@ -1,150 +1,137 @@
Ace (Ajax.org Cloud9 Editor) Ace (Ajax.org Cloud9 Editor)
============================ ============================
_Note_: The new site at http://ace.c9.io contains all the info below along with an embedding guide and all the other resources you need to get started with Ace. 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 [Cloud9 IDE](http://www.cloud9ide.com/) and the successor of the Mozilla Skywriter (Bespin) Project.
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 [Cloud9 IDE](https://c9.io/) and the successor of the Mozilla Skywriter (Bespin) Project.
Features Features
-------- --------
* Syntax highlighting for over 110 languages (TextMate/Sublime/_.tmlanguage_ files can be imported) * Syntax highlighting
* Over 20 themes (TextMate/Sublime/_.tmtheme_ files can be imported)
* Automatic indent and outdent * Automatic indent and outdent
* An optional command line * An optional command line
* Handles huge documents (at last check, 4,000,000 lines is the upper limit) * Handles huge documents (100,000 lines and more are no problem)
* Fully customizable key bindings including vim and Emacs modes * Fully customizable key bindings including VI and Emacs modes
* Themes (TextMate themes can be imported)
* Search and replace with regular expressions * Search and replace with regular expressions
* Highlight matching parentheses * Highlight matching parentheses
* Toggle between soft tabs and real tabs * Toggle between soft tabs and real tabs
* Displays hidden characters * Displays hidden characters
* Drag and drop text using the mouse * Drag and drop text using the mouse
* Line wrapping * Line wrapping
* Code folding * Unstructured / user code folding
* Multiple cursors and selections * Live syntax checker (currently JavaScript/CoffeeScript)
* Live syntax checker (currently JavaScript/CoffeeScript/CSS/XQuery)
* Cut, copy, and paste functionality
Take Ace for a spin! Take Ace for a spin!
-------------------- --------------------
Check out the Ace live [demo](http://ace.c9.io/build/kitchen-sink.html) or get a [Cloud9 IDE account](https://c9.io/) to experience Ace while editing one of your own GitHub projects. Check out the Ace live [demo](http://ajaxorg.github.com/ace/) or get a [Cloud9 IDE account](http://run.cloud9ide.com) to experience Ace while editing one of your own GitHub projects.
If you want, you can use Ace as a textarea replacement thanks to the [Ace Bookmarklet](http://ajaxorg.github.io/ace/build/demo/bookmarklet/index.html). If you want, you can use Ace as a textarea replacement thanks to the [Ace Bookmarklet](http://ajaxorg.github.com/ace/build/textarea/editor.html).
History
-------
Previously known as “Bespin” and “Skywriter” its 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.
Getting the code
----------------
Ace is a community project. We actively encourage and support contributions. The Ace source code is hosted on GitHub. It is released under the Mozilla tri-license (MPL/GPL/LGPL), the same license used by Firefox. This license 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!
git clone git://github.com/ajaxorg/ace.git
cd ace
git submodule update --init --recursive
Embedding Ace Embedding Ace
------------- -------------
Ace can be easily embedded into any existing web page. You can either use one of pre-packaged versions of [ace](https://github.com/ajaxorg/ace-builds/) (just copy one of `src*` subdirectories somewhere into your project), or use requireJS to load contents of [lib/ace](https://github.com/ajaxorg/ace/tree/master/lib/ace) as `ace` 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 `build` directory. The same packaged files are also available as a separate [download](https://github.com/ajaxorg/ace/downloads). Simply copy the contents of the `src` subdirectory somewhere into your project and take a look at the included demos of how to use Ace.
The easiest version is simply: The easiest version is simply:
```html
<div id="editor">some text</div> <div id="editor">some text</div>
<script src="src/ace.js" type="text/javascript" charset="utf-8"></script> <script src="src/ace.js" type="text/javascript" charset="utf-8"></script>
<script> <script>
window.onload = function() {
var editor = ace.edit("editor"); var editor = ace.edit("editor");
};
</script> </script>
```
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 `absolute` or `relative` for Ace to work. e.g. 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 `absolute` or `relative` for Ace to work. e.g.
```css
#editor { #editor {
position: absolute; position: absolute;
width: 500px; width: 500px;
height: 400px; height: 400px;
} }
```
To change the theme simply include the Theme's JavaScript file To change the theme simply include the Theme's JavaScript file
```html
<script src="src/theme-twilight.js" type="text/javascript" charset="utf-8"></script> <script src="src/theme-twilight.js" type="text/javascript" charset="utf-8"></script>
```
and configure the editor to use the theme: and configure the editor to use the theme:
```javascript
editor.setTheme("ace/theme/twilight"); editor.setTheme("ace/theme/twilight");
```
By default the editor only supports plain text mode; many other languages are available as separate modules. After including the mode's JavaScript file: By default the editor only supports plain text mode; many other languages are available as separate modules. After including the mode's JavaScript file:
```html
<script src="src/mode-javascript.js" type="text/javascript" charset="utf-8"></script> <script src="src/mode-javascript.js" type="text/javascript" charset="utf-8"></script>
```
The mode can then be used like this: Then the mode can be used like this:
```javascript var JavaScriptMode = require("ace/mode/javascript").Mode;
var JavaScriptMode = ace.require("ace/mode/javascript").Mode;
editor.getSession().setMode(new JavaScriptMode()); editor.getSession().setMode(new JavaScriptMode());
```
Documentation Documentation
------------- -------------
Additional usage information, including events to listen to and extending syntax highlighters, can be found [on the main Ace website](http://ace.c9.io). You find a lot more sample code in the [demo app](https://github.com/ajaxorg/ace/blob/master/demo/demo.js).
You can also find API documentation at [http://ace.c9.io/#nav=api](http://ace.c9.io/#nav=api). There is also some documentation on the [wiki page](https://github.com/ajaxorg/ace/wiki).
Also check out the sample code for the kitchen sink [demo app](https://github.com/ajaxorg/ace/blob/master/demo/kitchen-sink/demo.js). If you still need help, feel free to drop a mail on the [ace mailing list](http://groups.google.com/group/ace-discuss).
If you still need help, feel free to drop a mail on the [ace mailing list](http://groups.google.com/group/ace-discuss), or at `irc.freenode.net#ace`.
Running Ace Running Ace
----------- -----------
After the checkout Ace works out of the box. No build step is required. To try it out, simply start the bundled mini HTTP server: 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:
```bash
./static.py ./static.py
```
Or using Node.JS Or using Node.JS
```bash ./static.js
npm install mime
node ./static.js
```
The editor can then be opened at http://localhost:8888/kitchen-sink.html. The editor can then be opened at http://localhost:8888/index.html.
To open the editor with a file:/// URL see [the wiki](https://github.com/ajaxorg/ace/wiki/Running-Ace-from-file). Package Ace
Building Ace
----------- -----------
You do not generally need to build ACE. The [ace-builds repository](https://github.com/ajaxorg/ace-builds/) endeavours to maintain the latest build, and you can just copy one of _src*_ subdirectories somewhere into your project. 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.
However, all you need is Node.js and npm installed to package ACE. Just run `npm install` in the ace folder to install dependencies: git submodule update --init --recursive
```bash Afterwards Ace can be built by calling
npm install
node ./Makefile.dryice.js
```
To package Ace, we use the dryice build tool developed by the Mozilla Skywriter team. Call `node Makefile.dryice.js` on the command-line to start the packing. This build script accepts the following options ./Makefile.dryice.js normal
```bash The packaged Ace will be put in the 'build' folder.
-m minify build files with uglify-js
-nc namespace require and define calls with "ace"
-bm builds the bookmarklet version
--target ./path specify relative path for output folder (default value is "./build")
```
To generate all the files in the ace-builds repository, run `node Makefile.dryice.js full --target ../ace-builds` To build the bookmarklet version execute
./Makefile.dryice.js bm
Running the Unit Tests Running the Unit Tests
---------------------- ----------------------
The Ace unit tests can run on node.js. Assuming you have already done `npm install`, just call: 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
npm link .
To run the tests call:
```bash
node lib/ace/test/all.js node lib/ace/test/all.js
```
You can also run the tests in your browser by serving: You can also run the tests in your browser by serving:
@ -152,17 +139,23 @@ You can also run the tests in your browser by serving:
This makes debugging failing tests way more easier. This makes debugging failing tests way more easier.
_Note_: Currently (2011-05-21) the tests seem to run on Chrome only.
Contributing Contributing
----------------------------- ------------
Ace is a community project and wouldn't be what it is without contributions! We actively encourage and support contributions. The Ace source code 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! Ace wouldn't be where it is now without contributions. Feel free to fork and improve/enhance Ace in any way your 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:
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. For more information on our contributing guidelines, see [CONTRIBUTING.md](https://github.com/ajaxorg/ace/blob/master/CONTRIBUTING.md). 1. [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.
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
Continuous Integration status 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.
-----------------------------
This project is tested with [Travis CI](http://travis-ci.org) Email: fabian.jakobs@web.de
[![Build Status](https://secure.travis-ci.org/ajaxorg/ace.png?branch=master)](http://travis-ci.org/ajaxorg/ace)
Fax: +31 (0) 206388953
Address: Ajax.org B.V.
Keizersgracht 241
1016 EA, Amsterdam
the Netherlands

77
ace/ace.js Normal file
View file

@ -0,0 +1,77 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Skywriter.
*
* The Initial Developer of the Original Code is
* Mozilla.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Kevin Dangoor (kdangoor@mozilla.com)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
require("ace/lib/fixoldbrowsers");
var Dom = require("ace/lib/dom");
var Event = require("ace/lib/event");
var Editor = require("ace/editor").Editor;
var Buffer = require("ace/model/buffer").Buffer;
var Window = require("ace/model/window").Window;
var UndoManager = require("ace/undomanager").UndoManager;
var Renderer = require("ace/view/window_view").WindowView;
exports.edit = function(el) {
if (typeof(el) == "string") {
el = document.getElementById(el);
}
var doc = new Buffer(Dom.getInnerText(el));
doc.setUndoManager(new UndoManager());
el.innerHTML = '';
var theme = require("ace/theme/textmate");
var editor = new Editor(new Renderer(new Window(theme), el));
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;
};
});

192
ace/anchor.js Normal file
View file

@ -0,0 +1,192 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var EventEmitter = require("ace/lib/event_emitter").EventEmitter;
/**
* An Anchor is a floating pointer in the document. Whenever text is inserted or
* deleted before the cursor, the position of the cursor is updated
*/
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);
this.getPosition = function() {
return this.$clipPositionToDocument(this.row, this.column);
};
this.getDocument = function() {
return this.document;
};
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);
};
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._dispatchEvent("change", {
old: old,
value: pos
});
};
this.detach = function() {
this.document.removeEventListener("change", this.$onChange);
};
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);
});

View file

@ -1,44 +1,50 @@
/* ***** BEGIN LICENSE BLOCK ***** /* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
* *
* Copyright (c) 2010, Ajax.org B.V. * The contents of this file are subject to the Mozilla Public License Version
* All rights reserved. * 1.1 (the "License"); you may not use this file except in compliance with
* * the License. You may obtain a copy of the License at
* Redistribution and use in source and binary forms, with or without * http://www.mozilla.org/MPL/
* modification, are permitted provided that the following conditions are met: *
* * Redistributions of source code must retain the above copyright * Software distributed under the License is distributed on an "AS IS" basis,
* notice, this list of conditions and the following disclaimer. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* * Redistributions in binary form must reproduce the above copyright * for the specific language governing rights and limitations under the
* notice, this list of conditions and the following disclaimer in the * License.
* documentation and/or other materials provided with the distribution. *
* * Neither the name of Ajax.org B.V. nor the * The Original Code is Ajax.org Code Editor (ACE).
* names of its contributors may be used to endorse or promote products *
* derived from this software without specific prior written permission. * The Initial Developer of the Original Code is
* * Ajax.org B.V.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * Portions created by the Initial Developer are Copyright (C) 2010
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * the Initial Developer. All Rights Reserved.
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY * Contributor(s):
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * Fabian Jakobs <fabian AT ajax DOT org>
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; *
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * Alternatively, the contents of this file may be used under the terms of
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * either the GNU General Public License Version 2 or later (the "GPL"), or
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
* *
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
if (typeof process !== "undefined") { if (typeof process !== "undefined") {
require("amd-loader"); require("../support/paths");
} }
define(function(require, exports, module) { define(function(require, exports, module) {
"use strict";
var Document = require("ace/model/document").Document;
var Document = require("./document").Document; var Anchor = require("ace/anchor").Anchor;
var Anchor = require("./anchor").Anchor; var Range = require("ace/range").Range;
var Range = require("./range").Range; var assert = require("ace/test/assertions");
var assert = require("./test/assertions");
module.exports = { module.exports = {
@ -57,55 +63,20 @@ module.exports = {
doc.insert({row: 1, column: 1}, "123"); doc.insert({row: 1, column: 1}, "123");
assert.position(anchor.getPosition(), 1, 7); assert.position(anchor.getPosition(), 1, 7);
}, },
"test insert text at anchor should not move anchor when insertRight is true": function() {
var doc = new Document("juhu\nkinners");
var anchor = new Anchor(doc, 1, 4);
anchor.$insertRight = true;
doc.insert({row: 1, column: 4}, "123");
assert.position(anchor.getPosition(), 1, 4);
},
"test insert lines before cursor should move anchor row": function() { "test insert lines before cursor should move anchor row": function() {
var doc = new Document("juhu\nkinners"); var doc = new Document("juhu\nkinners");
var anchor = new Anchor(doc, 1, 4); var anchor = new Anchor(doc, 1, 4);
doc.insertFullLines(1, ["123", "456"]); doc.insertLines(1, ["123", "456"]);
assert.position(anchor.getPosition(), 3, 4); assert.position(anchor.getPosition(), 3, 4);
}, },
"test insert lines at anchor position should move anchor down": function() {
var doc = new Document("juhu\nkinners");
var anchor = new Anchor(doc, 1, 0);
doc.insertLines(1, ["line"]);
assert.position(anchor.getPosition(), 2, 0);
},
"test insert lines at anchor position should not move anchor down when insertRight is true and column is 0": function() {
var doc = new Document("juhu\nkinners");
var anchor = new Anchor(doc, 1, 0);
anchor.$insertRight = true;
doc.insertLines(1, ["line"]);
assert.position(anchor.getPosition(), 1, 0);
},
"test insert lines at anchor row should move anchor down when column > 0": function() {
var doc = new Document("juhu\nkinners");
var anchor = new Anchor(doc, 1, 2);
anchor.$insertRight = true;
doc.insertLines(1, ["line"]);
assert.position(anchor.getPosition(), 2, 2);
},
"test insert new line before cursor should move anchor column": function() { "test insert new line before cursor should move anchor column": function() {
var doc = new Document("juhu\nkinners"); var doc = new Document("juhu\nkinners");
var anchor = new Anchor(doc, 1, 4); var anchor = new Anchor(doc, 1, 4);
doc.insertMergedLines({row: 0, column: 0}, ['', '']); doc.insertNewLine({row: 0, column: 0});
assert.position(anchor.getPosition(), 2, 4); assert.position(anchor.getPosition(), 2, 4);
}, },
@ -113,7 +84,7 @@ module.exports = {
var doc = new Document("juhu\nkinners"); var doc = new Document("juhu\nkinners");
var anchor = new Anchor(doc, 1, 4); var anchor = new Anchor(doc, 1, 4);
doc.insertMergedLines({row: 1, column: 2}, ['', '']); doc.insertNewLine({row: 1, column: 2});
assert.position(anchor.getPosition(), 2, 2); assert.position(anchor.getPosition(), 2, 2);
}, },
@ -145,7 +116,7 @@ module.exports = {
var doc = new Document("juhu\n1\n2\nkinners"); var doc = new Document("juhu\n1\n2\nkinners");
var anchor = new Anchor(doc, 3, 4); var anchor = new Anchor(doc, 3, 4);
doc.removeFullLines(1, 2); doc.removeLines(1, 2);
assert.position(anchor.getPosition(), 1, 4); assert.position(anchor.getPosition(), 1, 4);
}, },
@ -169,7 +140,7 @@ module.exports = {
var doc = new Document("juhu\nkinners\n123"); var doc = new Document("juhu\nkinners\n123");
var anchor = new Anchor(doc, 1, 5); var anchor = new Anchor(doc, 1, 5);
doc.removeFullLines(1, 1); doc.removeLines(1, 1);
assert.position(anchor.getPosition(), 1, 0); assert.position(anchor.getPosition(), 1, 0);
}, },
@ -202,17 +173,6 @@ module.exports = {
}); });
doc.remove(new Range(2, 0, 2, 1)); doc.remove(new Range(2, 0, 2, 1));
},
"test insert/remove lines at the end of the document": function() {
var doc = new Document("juhu\nkinners\n123");
var anchor = new Anchor(doc, 2, 4);
doc.removeFullLines(0, 3);
assert.position(anchor.getPosition(), 0, 0);
doc.insertFullLines(0, ["a", "b", "c"]);
assert.position(anchor.getPosition(), 3, 0);
assert.equal(doc.getValue(), "a\nb\nc\n");
} }
}; };
@ -220,4 +180,4 @@ module.exports = {
if (typeof module !== "undefined" && module === require.main) { if (typeof module !== "undefined" && module === require.main) {
require("asyncjs").test.testcase(module.exports).exec() require("asyncjs").test.testcase(module.exports).exec()
} }

175
ace/background_tokenizer.js Normal file
View file

@ -0,0 +1,175 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var EventEmitter = require("ace/lib/event_emitter").EventEmitter;
var BackgroundTokenizer = function(tokenizer, editor) {
this.running = false;
this.lines = [];
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.lines[self.currentLine] = self.$tokenizeRows(self.currentLine, self.currentLine)[0];
self.currentLine++;
// only check every 5 lines
processedLines += 1;
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);
this.setTokenizer = function(tokenizer) {
this.tokenizer = tokenizer;
this.lines = [];
this.start(0);
};
this.setDocument = function(doc) {
this.doc = doc;
this.lines = [];
this.stop();
};
this.fireUpdateEvent = function(firstRow, lastRow) {
var data = {
first: firstRow,
last: lastRow
};
this._dispatchEvent("update", {data: data});
};
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.stop();
// pretty long delay to prevent the tokenizer from interfering with the user
this.running = setTimeout(this.$worker, 700);
};
this.stop = function() {
if (this.running)
clearTimeout(this.running);
this.running = false;
};
this.getTokens = function(firstRow, lastRow) {
return this.$tokenizeRows(firstRow, lastRow);
};
this.getState = function(row) {
return this.$tokenizeRows(row, row)[0].state;
};
this.$tokenizeRows = function(firstRow, lastRow) {
if (!this.doc)
return [];
var rows = [];
// determine start state
var state = "start";
var doCache = false;
if (firstRow > 0 && this.lines[firstRow - 1]) {
state = this.lines[firstRow - 1].state;
doCache = true;
} else if (firstRow == 0) {
state = "start";
doCache = true;
} else if (this.lines.length > 0) {
// Guess that we haven't changed state.
state = this.lines[this.lines.length-1].state;
}
var lines = this.doc.getLines(firstRow, lastRow);
for (var row=firstRow; row<=lastRow; row++) {
if (!this.lines[row]) {
var tokens = this.tokenizer.getLineTokens(lines[row-firstRow] || "", state);
var state = tokens.state;
rows.push(tokens);
if (doCache) {
this.lines[row] = tokens;
}
}
else {
var tokens = this.lines[row];
state = tokens.state;
rows.push(tokens);
}
}
return rows;
};
}).call(BackgroundTokenizer.prototype);
exports.BackgroundTokenizer = BackgroundTokenizer;
});

View file

@ -0,0 +1,87 @@
define(function(require, exports, module) {
var keyUtil = require("ace/lib/keys");
var useragent = require("ace/lib/useragent");
var CommandManager = function(commands) {
this.commands = {};
this.commmandKeyBinding = {};
if (commands)
commands.forEach(this.addCommand, this);
};
(function() {
this.addCommand = function(command) {
this.commands[command.name] = command;
if (command.bindKey) {
this._buildKeyHash(command);
}
};
var platform = useragent.isMac ? "mac" : "win";
this._buildKeyHash = function(command) {
var binding = command.bindKey;
var key = binding[platform];
var ckb = this.commmandKeyBinding;
if(!binding[platform]) {
return;
}
key.split("|").forEach(function(keyPart) {
var binding = parseKeys(keyPart, command);
var hashId = binding.hashId;
(ckb[hashId] || (ckb[hashId] = {}))[binding.key] = command;
});
}
function parseKeys(keys, val, ret) {
var key;
var hashId = 0;
var parts = splitSafe(keys, "\\-", null, true);
for (var i=0, l = parts.length; i < l; i++) {
if (keyUtil.KEY_MODS[parts[i]])
hashId = hashId | keyUtil.KEY_MODS[parts[i]];
else
key = parts[i] || "-"; //when empty, the splitSafe removed a '-'
}
return {
key: key,
hashId: hashId
}
}
function splitSafe(s, separator, limit, bLowerCase) {
return (bLowerCase && s.toLowerCase() || s)
.replace(/(?:^\s+|\n|\s+$)/g, "")
.split(new RegExp("[\\s ]*" + separator + "[\\s ]*", "g"), limit || 999);
}
this.findKeyCommand = function findKeyCommand(env, hashId, textOrKey) {
// Convert keyCode to the string representation.
if (typeof textOrKey == "number") {
textOrKey = keyUtil.keyCodeToString(textOrKey);
}
var ckbr = this.commmandKeyBinding;
return ckbr[hashId] && ckbr[hashId][textOrKey];
}
this.exec = function(command, env, args) {
if (typeof command === 'string')
command = this.commands[command];
command.exec(env, args || {});
};
}).call(CommandManager.prototype);
exports.CommandManager = CommandManager;
});

View file

@ -0,0 +1,307 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Julian Viereck <julian.viereck@gmail.com>
* Mihai Sucan <mihai.sucan@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var lang = require("ace/lib/lang");
function bindKey(win, mac) {
return {
win: win,
mac: mac,
sender: "editor"
};
}
exports.commands = [{
name: "selectall",
bindKey: bindKey("Ctrl-A", "Command-A"),
exec: function(env, args) { env.editor.selectAll(); }
}, {
name: "removeline",
bindKey: bindKey("Ctrl-D", "Command-D"),
exec: function(env, args) { env.editor.removeLines(); }
}, {
name: "gotoline",
bindKey: bindKey("Ctrl-L", "Command-L"),
exec: function(env, args) {
var line = parseInt(prompt("Enter line number:"));
if (!isNaN(line)) {
env.editor.gotoLine(line);
}
}
}, {
name: "togglecomment",
bindKey: bindKey("Ctrl-7", "Command-7"),
exec: function(env, args) { env.editor.toggleCommentLines(); }
}, {
name: "findnext",
bindKey: bindKey("Ctrl-K", "Command-G"),
exec: function(env, args) { env.editor.findNext(); }
}, {
name: "findprevious",
bindKey: bindKey("Ctrl-Shift-K", "Command-Shift-G"),
exec: function(env, args) { env.editor.findPrevious(); }
}, {
name: "find",
bindKey: bindKey("Ctrl-F", "Command-F"),
exec: function(env, args) {
var needle = prompt("Find:");
env.editor.find(needle);
}
}, {
name: "replace",
bindKey: bindKey("Ctrl-R", "Command-Option-F"),
exec: function(env, args) {
var needle = prompt("Find:");
if (!needle)
return;
var replacement = prompt("Replacement:");
if (!replacement)
return;
env.editor.replace(replacement, {needle: needle});
}
}, {
name: "replaceall",
bindKey: bindKey("Ctrl-Shift-R", "Command-Shift-Option-F"),
exec: function(env, args) {
var needle = prompt("Find:");
if (!needle)
return;
var replacement = prompt("Replacement:");
if (!replacement)
return;
env.editor.replaceAll(replacement, {needle: needle});
}
}, {
name: "undo",
bindKey: bindKey("Ctrl-Z", "Command-Z"),
exec: function(env, args) { env.editor.undo(); }
}, {
name: "redo",
bindKey: bindKey("Ctrl-Shift-Z|Ctrl-Y", "Command-Shift-Z|Command-Y"),
exec: function(env, args) { env.editor.redo(); }
}, {
name: "overwrite",
bindKey: bindKey("Insert", "Insert"),
exec: function(env, args) { env.editor.toggleOverwrite(); }
}, {
name: "copylinesup",
bindKey: bindKey("Ctrl-Alt-Up", "Command-Option-Up"),
exec: function(env, args) { env.editor.copyLinesUp(); }
}, {
name: "movelinesup",
bindKey: bindKey("Alt-Up", "Option-Up"),
exec: function(env, args) { env.editor.moveLinesUp(); }
}, {
name: "selecttostart",
bindKey: bindKey("Ctrl-Shift-Home|Alt-Shift-Up", "Command-Shift-Up"),
exec: function(env, args) { env.editor.getSelection().selectFileStart(); }
}, {
name: "gotostart",
bindKey: bindKey("Ctrl-Home|Ctrl-Up", "Command-Home|Command-Up"),
exec: function(env, args) { env.editor.navigateFileStart(); }
}, {
name: "selectup",
bindKey: bindKey("Shift-Up", "Shift-Up"),
exec: function(env, args) { env.editor.getSelection().selectUp(); }
}, {
name: "golineup",
bindKey: bindKey("Up", "Up|Ctrl-P"),
exec: function(env, args) { env.editor.navigateUp(args.times); }
}, {
name: "copylinesdown",
bindKey: bindKey("Ctrl-Alt-Down", "Command-Option-Down"),
exec: function(env, args) { env.editor.copyLinesDown(); }
}, {
name: "movelinesdown",
bindKey: bindKey("Alt-Down", "Option-Down"),
exec: function(env, args) { env.editor.moveLinesDown(); }
}, {
name: "selecttoend",
bindKey: bindKey("Ctrl-Shift-End|Alt-Shift-Down", "Command-Shift-Down"),
exec: function(env, args) { env.editor.getSelection().selectFileEnd(); }
}, {
name: "gotoend",
bindKey: bindKey("Ctrl-End|Ctrl-Down", "Command-End|Command-Down"),
exec: function(env, args) { env.editor.navigateFileEnd(); }
}, {
name: "selectdown",
bindKey: bindKey("Shift-Down", "Shift-Down"),
exec: function(env, args) { env.editor.getSelection().selectDown(); }
}, {
name: "golinedown",
bindKey: bindKey("Down", "Down|Ctrl-N"),
exec: function(env, args) { env.editor.navigateDown(args.times); }
}, {
name: "selectwordleft",
bindKey: bindKey("Ctrl-Shift-Left", "Option-Shift-Left"),
exec: function(env, args) { env.editor.getSelection().selectWordLeft(); }
}, {
name: "gotowordleft",
bindKey: bindKey("Ctrl-Left", "Option-Left"),
exec: function(env, args) { env.editor.navigateWordLeft(); }
}, {
name: "selecttolinestart",
bindKey: bindKey("Alt-Shift-Left", "Command-Shift-Left"),
exec: function(env, args) { env.editor.getSelection().selectLineStart(); }
}, {
name: "gotolinestart",
bindKey: bindKey("Alt-Left|Home", "Command-Left|Home|Ctrl-A"),
exec: function(env, args) { env.editor.navigateLineStart(); }
}, {
name: "selectleft",
bindKey: bindKey("Shift-Left", "Shift-Left"),
exec: function(env, args) { env.editor.getSelection().selectLeft(); }
}, {
name: "gotoleft",
bindKey: bindKey("Left", "Left|Ctrl-B"),
exec: function(env, args) { env.editor.navigateLeft(args.times); }
}, {
name: "selectwordright",
bindKey: bindKey("Ctrl-Shift-Right", "Option-Shift-Right"),
exec: function(env, args) { env.editor.getSelection().selectWordRight(); }
}, {
name: "gotowordright",
bindKey: bindKey("Ctrl-Right", "Option-Right"),
exec: function(env, args) { env.editor.navigateWordRight(); }
}, {
name: "selecttolineend",
bindKey: bindKey("Alt-Shift-Right", "Command-Shift-Right"),
exec: function(env, args) { env.editor.getSelection().selectLineEnd(); }
}, {
name: "gotolineend",
bindKey: bindKey("Alt-Right|End", "Command-Right|End|Ctrl-E"),
exec: function(env, args) { env.editor.navigateLineEnd(); }
}, {
name: "selectright",
bindKey: bindKey("Shift-Right", "Shift-Right"),
exec: function(env, args) { env.editor.getSelection().selectRight(); }
}, {
name: "gotoright",
bindKey: bindKey("Right", "Right|Ctrl-F"),
exec: function(env, args) { env.editor.navigateRight(args.times); }
}, {
name: "selectpagedown",
bindKey: bindKey("Shift-PageDown", "Shift-PageDown"),
exec: function(env, args) { env.editor.selectPageDown(); }
}, {
name: "pagedown",
bindKey: bindKey(null, "PageDown"),
exec: function(env, args) { env.editor.scrollPageDown(); }
}, {
name: "gotopagedown",
bindKey: bindKey("PageDown", "Option-PageDown|Ctrl-V"),
exec: function(env, args) { env.editor.gotoPageDown(); }
}, {
name: "selectpageup",
bindKey: bindKey("Shift-PageUp", "Shift-PageUp"),
exec: function(env, args) { env.editor.selectPageUp(); }
}, {
name: "pageup",
bindKey: bindKey(null, "PageUp"),
exec: function(env, args) { env.editor.scrollPageUp(); }
}, {
name: "gotopageup",
bindKey: bindKey("PageUp", "Option-PageUp"),
exec: function(env, args) { env.editor.gotoPageUp(); }
}, {
name: "selectlinestart",
bindKey: bindKey("Shift-Home", "Shift-Home"),
exec: function(env, args) { env.editor.getSelection().selectLineStart(); }
}, {
name: "selectlineend",
bindKey: bindKey("Shift-End", "Shift-End"),
exec: function(env, args) { env.editor.getSelection().selectLineEnd(); }
}, {
name: "del",
bindKey: bindKey("Delete", "Delete|Ctrl-D"),
exec: function(env, args) { env.editor.removeRight(); }
}, {
name: "backspace",
bindKey: bindKey(
"Ctrl-Backspace|Command-Backspace|Option-Backspace|Shift-Backspace|Backspace",
"Ctrl-Backspace|Command-Backspace|Shift-Backspace|Backspace|Ctrl-H"
),
exec: function(env, args) { env.editor.removeLeft(); }
}, {
name: "removetolinestart",
bindKey: bindKey(null, "Option-Backspace"),
exec: function(env, args) { env.editor.removeToLineStart(); }
}, {
name: "removetolineend",
bindKey: bindKey(null, "Ctrl-K"),
exec: function(env, args) { env.editor.removeToLineEnd(); }
}, {
name: "removewordleft",
bindKey: bindKey("Ctrl-Backspace", "Alt-Backspace|Ctrl-Alt-Backspace"),
exec: function(env, args) { env.editor.removeWordLeft(); }
}, {
name: "removewordright",
bindKey: bindKey(null, "Alt-Delete"),
exec: function(env, args) { env.editor.removeWordRight(); }
}, {
name: "outdent",
bindKey: bindKey("Shift-Tab", "Shift-Tab"),
exec: function(env, args) { env.editor.blockOutdent(); }
}, {
name: "indent",
bindKey: bindKey("Tab", "Tab"),
exec: function(env, args) { env.editor.indent(); }
}, {
name: "inserttext",
exec: function(env, args) {
env.editor.insert(lang.stringRepeat(args.text || "", args.times || 1));
}
}, {
name: "centerselection",
bindKey: bindKey(null, "Ctrl-L"),
exec: function(env, args) { env.editor.centerSelection(); }
}, {
name: "splitline",
bindKey: bindKey(null, "Ctrl-O"),
exec: function(env, args) { env.editor.splitLine(); }
}, {
name: "transposeletters",
bindKey: bindKey("Ctrl-T", "Ctrl-T"),
exec: function(env, args) { env.editor.transposeLetters(); }
}];
});

79
ace/edit_session/fold.js Normal file
View file

@ -0,0 +1,79 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Julian Viereck <julian DOT viereck AT gmail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
/**
* 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;
};
}).call(Fold.prototype);
});

View file

@ -1,40 +1,47 @@
/* ***** BEGIN LICENSE BLOCK ***** /* vim:ts=4:sts=4:sw=4:
* Distributed under the BSD license: * ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
* *
* Copyright (c) 2010, Ajax.org B.V. * The contents of this file are subject to the Mozilla Public License Version
* All rights reserved. * 1.1 (the "License"); you may not use this file except in compliance with
* * the License. You may obtain a copy of the License at
* Redistribution and use in source and binary forms, with or without * http://www.mozilla.org/MPL/
* modification, are permitted provided that the following conditions are met: *
* * Redistributions of source code must retain the above copyright * Software distributed under the License is distributed on an "AS IS" basis,
* notice, this list of conditions and the following disclaimer. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* * Redistributions in binary form must reproduce the above copyright * for the specific language governing rights and limitations under the
* notice, this list of conditions and the following disclaimer in the * License.
* documentation and/or other materials provided with the distribution. *
* * Neither the name of Ajax.org B.V. nor the * The Original Code is Ajax.org Code Editor (ACE).
* names of its contributors may be used to endorse or promote products *
* derived from this software without specific prior written permission. * The Initial Developer of the Original Code is
* * Ajax.org B.V.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * Portions created by the Initial Developer are Copyright (C) 2010
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * the Initial Developer. All Rights Reserved.
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY * Contributor(s):
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * Julian Viereck <julian DOT viereck AT gmail DOT com>
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; *
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * Alternatively, the contents of this file may be used under the terms of
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * either the GNU General Public License Version 2 or later (the "GPL"), or
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
* *
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) { define(function(require, exports, module) {
"use strict";
var Range = require("../range").Range; var Range = require("ace/range").Range;
/* /**
* If an array is passed in, the folds are expected to be sorted already. * If the an array is passed in, the folds are expected to be sorted already.
*/ */
function FoldLine(foldData, folds) { function FoldLine(foldData, folds) {
this.foldData = foldData; this.foldData = foldData;
@ -44,7 +51,7 @@ function FoldLine(foldData, folds) {
folds = this.folds = [ folds ]; folds = this.folds = [ folds ];
} }
var last = folds[folds.length - 1]; var last = folds[folds.length - 1]
this.range = new Range(folds[0].start.row, folds[0].start.column, this.range = new Range(folds[0].start.row, folds[0].start.column,
last.end.row, last.end.column); last.end.row, last.end.column);
this.start = this.range.start; this.start = this.range.start;
@ -56,7 +63,7 @@ function FoldLine(foldData, folds) {
} }
(function() { (function() {
/* /**
* Note: This doesn't update wrapData! * Note: This doesn't update wrapData!
*/ */
this.shiftRow = function(shift) { this.shiftRow = function(shift) {
@ -66,12 +73,12 @@ function FoldLine(foldData, folds) {
fold.start.row += shift; fold.start.row += shift;
fold.end.row += shift; fold.end.row += shift;
}); });
}; }
this.addFold = function(fold) { this.addFold = function(fold) {
if (fold.sameRow) { if (fold.sameRow) {
if (fold.start.row < this.startRow || fold.endRow > this.endRow) { if (fold.start.row < this.startRow || fold.endRow > this.endRow) {
throw new Error("Can't add a fold to this FoldLine as it has no connection"); throw "Can't add a fold to this FoldLine as it has no connection";
} }
this.folds.push(fold); this.folds.push(fold);
this.folds.sort(function(a, b) { this.folds.sort(function(a, b) {
@ -93,20 +100,20 @@ function FoldLine(foldData, folds) {
this.start.row = fold.start.row; this.start.row = fold.start.row;
this.start.column = fold.start.column; this.start.column = fold.start.column;
} else { } else {
throw new Error("Trying to add fold to FoldRow that doesn't have a matching row"); throw "Trying to add fold to FoldRow that doesn't have a matching row";
} }
fold.foldLine = this; fold.foldLine = this;
}; }
this.containsRow = function(row) { this.containsRow = function(row) {
return row >= this.start.row && row <= this.end.row; return row >= this.start.row && row <= this.end.row;
}; }
this.walk = function(callback, endRow, endColumn) { this.walk = function(callback, endRow, endColumn) {
var lastEnd = 0, var lastEnd = 0,
folds = this.folds, folds = this.folds,
fold, fold,
cmp, stop, isNewRow = true; comp, stop, isNewRow = true;
if (endRow == null) { if (endRow == null) {
endRow = this.end.row; endRow = this.end.row;
@ -116,9 +123,9 @@ function FoldLine(foldData, folds) {
for (var i = 0; i < folds.length; i++) { for (var i = 0; i < folds.length; i++) {
fold = folds[i]; fold = folds[i];
cmp = fold.range.compareStart(endRow, endColumn); comp = fold.range.compareStart(endRow, endColumn);
// This fold is after the endRow/Column. // This fold is after the endRow/Column.
if (cmp == -1) { if (comp == -1) {
callback(null, endRow, endColumn, lastEnd, isNewRow); callback(null, endRow, endColumn, lastEnd, isNewRow);
return; return;
} }
@ -127,8 +134,8 @@ function FoldLine(foldData, folds) {
stop = !stop && callback(fold.placeholder, fold.start.row, fold.start.column, lastEnd); stop = !stop && callback(fold.placeholder, fold.start.row, fold.start.column, lastEnd);
// If the user requested to stop the walk or endRow/endColumn is // If the user requested to stop the walk or endRow/endColumn is
// inside of this fold (cmp == 0), then end here. // inside of this fold (comp == 0), then end here.
if (stop || cmp === 0) { if (stop || comp == 0) {
return; return;
} }
@ -138,7 +145,7 @@ function FoldLine(foldData, folds) {
lastEnd = fold.end.column; lastEnd = fold.end.column;
} }
callback(null, endRow, endColumn, lastEnd, isNewRow); callback(null, endRow, endColumn, lastEnd, isNewRow);
}; }
this.getNextFoldTo = function(row, column) { this.getNextFoldTo = function(row, column) {
var fold, cmp; var fold, cmp;
@ -150,15 +157,15 @@ function FoldLine(foldData, folds) {
fold: fold, fold: fold,
kind: "after" kind: "after"
}; };
} else if (cmp === 0) { } else if (cmp == 0) {
return { return {
fold: fold, fold: fold,
kind: "inside" kind: "inside"
}; }
} }
} }
return null; return null;
}; }
this.addRemoveChars = function(row, column, len) { this.addRemoveChars = function(row, column, len) {
var ret = this.getNextFoldTo(row, column), var ret = this.getNextFoldTo(row, column),
@ -169,13 +176,11 @@ function FoldLine(foldData, folds) {
&& fold.start.column != column && fold.start.column != column
&& fold.start.row != row) && fold.start.row != row)
{ {
//throwing here breaks whole editor throw "Moving characters inside of a fold should never be reached";
//TODO: properly handle this
window.console && window.console.log(row, column, fold);
} else if (fold.start.row == row) { } else if (fold.start.row == row) {
folds = this.folds; folds = this.folds;
var i = folds.indexOf(fold); var i = folds.indexOf(fold);
if (i === 0) { if (i == 0) {
this.start.column += len; this.start.column += len;
} }
for (i; i < folds.length; i++) { for (i; i < folds.length; i++) {
@ -189,18 +194,16 @@ function FoldLine(foldData, folds) {
this.end.column += len; this.end.column += len;
} }
} }
}; }
this.split = function(row, column) { this.split = function(row, column) {
var pos = this.getNextFoldTo(row, column); var fold = this.getNextFoldTo(row, column).fold,
folds = this.folds;
if (!pos || pos.kind == "inside")
return null;
var fold = pos.fold;
var folds = this.folds;
var foldData = this.foldData; var foldData = this.foldData;
if (!fold) {
return null;
}
var i = folds.indexOf(fold); var i = folds.indexOf(fold);
var foldBefore = folds[i - 1]; var foldBefore = folds[i - 1];
this.end.row = foldBefore.end.row; this.end.row = foldBefore.end.row;
@ -213,7 +216,7 @@ function FoldLine(foldData, folds) {
var newFoldLine = new FoldLine(foldData, folds); var newFoldLine = new FoldLine(foldData, folds);
foldData.splice(foldData.indexOf(this) + 1, 0, newFoldLine); foldData.splice(foldData.indexOf(this) + 1, 0, newFoldLine);
return newFoldLine; return newFoldLine;
}; }
this.merge = function(foldLineNext) { this.merge = function(foldLineNext) {
var folds = foldLineNext.folds; var folds = foldLineNext.folds;
@ -224,7 +227,7 @@ function FoldLine(foldData, folds) {
// it's merged now with foldLineNext. // it's merged now with foldLineNext.
var foldData = this.foldData; var foldData = this.foldData;
foldData.splice(foldData.indexOf(foldLineNext), 1); foldData.splice(foldData.indexOf(foldLineNext), 1);
}; }
this.toString = function() { this.toString = function() {
var ret = [this.range.toString() + ": [" ]; var ret = [this.range.toString() + ": [" ];
@ -232,12 +235,13 @@ function FoldLine(foldData, folds) {
this.folds.forEach(function(fold) { this.folds.forEach(function(fold) {
ret.push(" " + fold.toString()); ret.push(" " + fold.toString());
}); });
ret.push("]"); ret.push("]")
return ret.join("\n"); return ret.join("\n");
}; }
this.idxToPosition = function(idx) { this.idxToPosition = function(idx) {
var lastFoldEndColumn = 0; var lastFoldEndColumn = 0;
var fold;
for (var i = 0; i < this.folds.length; i++) { for (var i = 0; i < this.folds.length; i++) {
var fold = this.folds[i]; var fold = this.folds[i];
@ -262,8 +266,8 @@ function FoldLine(foldData, folds) {
row: this.end.row, row: this.end.row,
column: this.end.column + idx column: this.end.column + idx
}; };
}; }
}).call(FoldLine.prototype); }).call(FoldLine.prototype);
exports.FoldLine = FoldLine; exports.FoldLine = FoldLine;
}); });

496
ace/edit_session/folding.js Normal file
View file

@ -0,0 +1,496 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Julian Viereck <julian DOT viereck AT gmail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var Range = require("ace/range").Range;
var FoldLine = require("ace/edit_session/fold_line").FoldLine;
var Fold = require("ace/edit_session/fold").Fold;
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 the string between folds at the given position.
* E.g.
* foo<fold>b|ar<fold>wolrd -> "bar"
* foo<fold>bar<fold>wol|rd -> "world"
* foo<fold>bar<fo|ld>wolrd -> <null>
*
* 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.
* foo<fold>b|ar<fold>wolrd -trim=-1> "b"
* foo<fold>bar<fold>wol|rd -trim=+1> "rld"
* fo|o<fold>bar<fold>wolrd -trim=00> "foo"
*/
this.getFoldStringAt = function(row, column, trim, foldLine) {
var foldLine = foldLine || this.getFoldLine(row);
if (!foldLine)
return null;
var lastFold = {
end: { column: 0 }
};
// TODO: Refactor to use getNextFoldTo function.
for (var i = 0; i < foldLine.folds.length; i++) {
var fold = foldLine.folds[i];
var cmp = fold.range.compareEnd(row, column);
if (cmp == -1) {
var 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.getNextFold = function(docRow, startFoldLine) {
var foldData = this.$foldData, ans;
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;
if (placeholder instanceof Fold)
var fold = placeholder;
else
fold = new Fold(range, placeholder);
var startRow = fold.start.row;
var startColumn = fold.start.column;
var endRow = fold.end.row;
var endColumn = fold.end.column;
// --- Some checking ---
if (fold.placeholder.length < 2)
throw "Placeholder has to be at least 2 characters";
if (startRow == endRow && endColumn - startColumn < 2)
throw "The range has to be at least 2 characters width";
var existingFold = this.getFoldAt(startRow, startColumn, 1);
if (
existingFold
&& existingFold.range.isEnd(endRow, endColumn)
&& existingFold.range.isStart(startRow, startColumn)
) {
return fold;
}
existingFold = this.getFoldAt(startRow, startColumn, 1);
if (existingFold && !existingFold.range.isStart(startRow, startColumn))
throw "A fold can't start inside of an already existing fold";
existingFold = this.getFoldAt(endRow, endColumn, -1);
if (existingFold && !existingFold.range.isEnd(endRow, endColumn))
throw "A fold can't end inside of an already existing fold";
if (endRow >= this.doc.getLength())
throw "End of fold is outside of the document.";
if (endColumn > this.getLine(endRow).length || startColumn > this.getLine(startRow).length)
throw "End of fold is outside of the document.";
// 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.
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);
// Notify that fold data has changed.
this.$modified = true;
this._dispatchEvent("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,
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.
{
var newFoldLine = foldLine.split(fold.start.row, fold.start.column);
newFoldLine.folds.shift();
foldLine.start.row = folds[0].start.row;
foldLine.start.column = folds[0].start.column;
this.$addFoldLine(newFoldLine);
}
if (this.$useWrapMode) {
this.$updateWrapData(startRow, endRow);
}
// Notify that fold data has changed.
this.$modified = true;
this._dispatchEvent("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);
}
/**
* 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 line = "";
var doc = this.doc;
var textLine = "";
foldLine.walk(function(placeholder, row, column, lastColumn, isNewRow) {
if (row < startRow) {
return;
} else if (row == startRow) {
if (column < startColumn) {
return;
}
lastColumn = Math.max(startColumn, lastColumn);
}
if (placeholder) {
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 foldData = this.$foldData;
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;
};
}
exports.Folding = Folding;
});

909
ace/editor.js Normal file
View file

@ -0,0 +1,909 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)
* Julian Viereck <julian.viereck@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
require("ace/lib/fixoldbrowsers");
var oop = require("ace/lib/oop");
var event = require("ace/lib/event");
var lang = require("ace/lib/lang");
var useragent = require("ace/lib/useragent");
var TextInput = require("ace/keyboard/textinput").TextInput;
var MouseHandler = require("ace/mouse_handler").MouseHandler;
//var TouchHandler = require("ace/touch_handler").TouchHandler;
var KeyBinding = require("ace/keyboard/keybinding").KeyBinding;
var Buffer = require("ace/model/buffer").Buffer;
var Window = require("ace/model/window").Window;
var WindowController = require("ace/window_controller").WindowController;
var Search = require("ace/search").Search;
var Range = require("ace/range").Range;
var EventEmitter = require("ace/lib/event_emitter").EventEmitter;
var CommandManager = require("ace/commands/command_manager").CommandManager;
var defaultCommands = require("ace/commands/default_commands").commands;
var Editor = function(windowView, buffer) {
var container = windowView.getContainerElement();
this.container = container;
this.renderer = windowView;
this.textInput = new TextInput(windowView.getTextAreaContainer(), this);
this.keyBinding = new KeyBinding(this);
// TODO detect touch event support
if (useragent.isIPad) {
//this.$mouseHandler = new TouchHandler(this);
} else {
this.$mouseHandler = new MouseHandler(this);
}
this.windowModel = this.renderer.model;
this.windowModel.search = new Search().set({
wrap: true
});
this.windowController = new WindowController(this.windowModel, this.renderer);
this.commands = new CommandManager(defaultCommands);
this.setSession(buffer || new Buffer(""));
};
(function(){
oop.implement(this, EventEmitter);
this.$forwardEvents = {
gutterclick: 1,
gutterdblclick: 1
};
this.$originalAddEventListener = this.addEventListener;
this.$originalRemoveEventListener = this.removeEventListener;
this.addEventListener = function(eventName, callback) {
if (this.$forwardEvents[eventName]) {
return this.renderer.addEventListener(eventName, callback);
} else {
return this.$originalAddEventListener(eventName, callback);
}
};
this.removeEventListener = function(eventName, callback) {
if (this.$forwardEvents[eventName]) {
return this.renderer.removeEventListener(eventName, callback);
} else {
return this.$originalRemoveEventListener(eventName, callback);
}
};
this.setKeyboardHandler = function(keyboardHandler) {
this.keyBinding.setKeyboardHandler(keyboardHandler);
};
this.getKeyboardHandler = function() {
return this.keyBinding.getKeyboardHandler();
};
// TODO refactor
// remove
this.setSession = function(session) {
if (this.session == session)
return;
this.windowModel.setBuffer(session);
this.session = session;
this.selection = session.getSelection();
};
this.getSession = function() {
return this.session;
};
this.getSelection = function() {
return this.selection;
};
this.resize = function() {
//this.renderer.onResize();
this.windowController.resize();
};
this.setTheme = function(theme) {
this.windowModel.setTheme(theme);
};
this.getTheme = function() {
return this.windowModel.getTheme();
};
this.setStyle = function(style) {
this.renderer.setStyle(style);
};
this.unsetStyle = function(style) {
this.renderer.unsetStyle(style);
};
this.setFontSize = function(size) {
this.container.style.fontSize = size;
};
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();
};
this.isFocused = function() {
return this.textInput.isFocused();
};
this.blur = function() {
this.textInput.blur();
};
this.onFocus = function() {
this.renderer.showCursor();
this.renderer.visualizeFocus();
this._dispatchEvent("focus");
};
this.onBlur = function() {
this.renderer.hideCursor();
this.renderer.visualizeBlur();
this._dispatchEvent("blur");
};
this.getCopyText = function() {
var text = "";
if (!this.selection.isEmpty())
text = this.session.getTextRange(this.getSelectionRange());
this._emit("copy", text);
return text;
};
this.onCut = function() {
if (this.$readOnly)
return;
var range = this.getSelectionRange();
this._emit("cut", range);
if (!this.selection.isEmpty()) {
this.session.remove(range)
this.clearSelection();
}
};
this.insert = function(text) {
if (this.$readOnly)
return;
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()) {
var 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 shouldOutdent = mode.checkOutdent(lineState, session.getLine(cursor.row), text);
var line = session.getLine(cursor.row);
var lineIndent = mode.getNextLineIndent(lineState, line.slice(0, cursor.column), session.getTabString());
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]));
}
}
var lineState = session.getState(cursor.row);
// TODO disabled multiline auto indent
// possibly doing the indent before inserting the text
// if (cursor.row !== end.row) {
if (session.getDocument().isNewLine(text)) {
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);
} else {
if (shouldOutdent) {
mode.autoOutdent(lineState, session, cursor.row);
}
}
};
this.onTextInput = function(text) {
// In case we got only one character, then
// handel it as a command key stroke.
if (text.length == 1) {
// Note: The `null` as `keyCode` is important here, as there are
// some checks in the code for `keyCode == 0` meaning the text comes
// from the keyBinding.onTextInput code path.
var handled = this.keyBinding.onCommandKey({}, 0, null, text);
// Check if the text was handled. If not, then handled it as "normal"
// text and insert it to the editor directly. This shouldn't be done
// using the this.keyBinding.onTextInput(text) function, as it would
// make the `text` get sent to the keyboardHandler twice, which might
// turn out to be a bad thing in case there is a custome keyboard
// handler like the StateHandler.
if (!handled) {
this.insert(text);
}
} else {
this.keyBinding.onTextInput(text);
}
};
this.onPaste = function(text) {
this._emit("paste", text);
this.keyBinding.onTextInput(text);
};
this.onCommandKey = function(e, hashId, keyCode) {
this.keyBinding.onCommandKey(e, hashId, keyCode);
};
this.setOverwrite = function(overwrite) {
this.session.setOverwrite(overwrite);
};
this.getOverwrite = function() {
return this.session.getOverwrite();
};
this.toggleOverwrite = function() {
this.session.toggleOverwrite();
};
this.setScrollSpeed = function(speed) {
this.$mouseHandler.setScrollSpeed(speed);
};
this.getScrollSpeed = function() {
return this.$mouseHandler.getScrollSpeed()
};
this.setSelectionStyle = function(style) {
this.windowModel.setSelectionStyle(style);
};
this.getSelectionStyle = function() {
return this.windowModel.getSelectionStyle();
};
this.setHighlightActiveLine = function(shouldHighlight) {
this.windowModel.setHighlightActiveLine(shouldHighlight);
};
this.getHighlightActiveLine = function() {
return this.windowModel.getHighlightActiveLine();
};
this.setHighlightSelectedWord = function(shouldHighlight) {
this.windowModel.setHighlightSelectedWord(shouldHighlight);
};
this.getHighlightSelectedWord = function() {
return this.windowModel.getHighlightSelectedWord();
};
this.setShowInvisibles = function(showInvisibles) {
this.windowModel.setShowInvisibles(showInvisibles);
};
this.getShowInvisibles = function() {
return this.windowModel.getShowInvisibles();
};
this.setShowPrintMargin = function(showPrintMargin) {
this.windowModel.setShowPrintMargin(showPrintMargin);
};
this.getShowPrintMargin = function() {
return this.windowModel.getShowPrintMargin();
};
this.setPrintMarginColumn = function(showPrintMargin) {
this.windowModel.setPrintMarginColumn(showPrintMargin);
};
this.getPrintMarginColumn = function() {
return this.windowModel.getPrintMarginColumn();
};
this.setShowGutter = function(showGutter) {
this.windowModel.setShowGutter(showGutter);
};
this.getShowGutter = function() {
return this.windowModel.getShowGutter();
};
this.setHScrollBarAlwaysVisible = function(alwaysVisible) {
this.windowModel.setHScrollBarAlwaysVisible(alwaysVisible);
};
this.getHScrollBarAlwaysVisible = function() {
return this.windowModel.getHScrollBarAlwaysVisible();
};
this.$readOnly = false;
this.setReadOnly = function(readOnly) {
this.$readOnly = readOnly;
};
this.getReadOnly = function() {
return this.$readOnly;
};
this.$modeBehaviours = true;
this.setBehavioursEnabled = function (enabled) {
this.$modeBehaviours = enabled;
}
this.getBehavioursEnabled = function () {
return this.$modeBehaviours;
}
this.removeRight = function() {
if (this.$readOnly)
return;
if (this.selection.isEmpty()) {
this.selection.selectRight();
}
this.session.remove(this.getSelectionRange())
this.clearSelection();
};
this.removeLeft = function() {
if (this.$readOnly)
return;
if (this.selection.isEmpty())
this.selection.selectLeft();
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 !== false) {
range = new_range;
}
}
this.session.remove(range);
this.clearSelection();
};
this.removeWordRight = function() {
if (this.$readOnly)
return;
if (this.selection.isEmpty())
this.selection.selectWordRight();
this.session.remove(this.getSelectionRange());
this.clearSelection();
};
this.removeWordLeft = function() {
if (this.$readOnly)
return;
if (this.selection.isEmpty())
this.selection.selectWordLeft();
this.session.remove(this.getSelectionRange());
this.clearSelection();
};
this.removeToLineStart = function() {
if (this.$readOnly)
return;
if (this.selection.isEmpty())
this.selection.selectLineStart();
this.session.remove(this.getSelectionRange());
this.clearSelection();
};
this.removeToLineEnd = function() {
if (this.$readOnly)
return;
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();
};
this.splitLine = function() {
if (this.$readOnly)
return;
if (!this.selection.isEmpty()) {
this.session.remove(this.getSelectionRange());
this.clearSelection();
}
var cursor = this.getCursorPosition();
this.insert("\n");
this.moveCursorToPosition(cursor);
};
this.transposeLetters = function() {
if (this.$readOnly)
return;
if (!this.selection.isEmpty()) {
return;
}
var cursor = this.getCursorPosition();
var column = cursor.column;
if (column == 0)
return;
var line = this.session.getLine(cursor.row);
if (column < line.length) {
var swap = line.charAt(column) + line.charAt(column-1);
var range = new Range(cursor.row, column-1, cursor.row, column+1)
}
else {
var swap = line.charAt(column-1) + line.charAt(column-2);
var range = new Range(cursor.row, column-2, cursor.row, column)
}
this.session.replace(range, swap);
};
this.indent = function() {
if (this.$readOnly)
return;
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.onTextInput(indentString);
}
};
this.blockOutdent = function() {
if (this.$readOnly)
return;
var selection = this.session.getSelection();
this.session.outdentRows(selection.getRange());
};
this.toggleCommentLines = function() {
if (this.$readOnly)
return;
var state = this.session.getState(this.getCursorPosition().row);
var rows = this.$getSelectedRows()
this.session.getMode().toggleCommentLines(state, this.session, rows.first, rows.last);
};
this.removeLines = function() {
if (this.$readOnly)
return;
var rows = this.$getSelectedRows();
if (rows.last == 0 || rows.last+1 < this.session.getLength())
var range = new Range(rows.first, 0, rows.last+1, 0)
else
var 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.moveLinesDown = function() {
if (this.$readOnly)
return;
this.$moveLines(function(firstRow, lastRow) {
return this.session.moveLinesDown(firstRow, lastRow);
});
};
this.moveLinesUp = function() {
if (this.$readOnly)
return;
this.$moveLines(function(firstRow, lastRow) {
return this.session.moveLinesUp(firstRow, lastRow);
});
};
this.moveText = function(range, toPosition) {
if (this.$readOnly)
return null;
return this.session.moveText(range, toPosition);
};
this.copyLinesUp = function() {
if (this.$readOnly)
return;
this.$moveLines(function(firstRow, lastRow) {
this.session.duplicateLines(firstRow, lastRow);
return 0;
});
};
this.copyLinesDown = function() {
if (this.$readOnly)
return;
this.$moveLines(function(firstRow, lastRow) {
return this.session.duplicateLines(firstRow, lastRow);
});
};
this.$moveLines = function(mover) {
var rows = this.$getSelectedRows();
var linesMoved = mover.call(this, rows.first, rows.last);
var selection = this.selection;
selection.setSelectionAnchor(rows.last+linesMoved+1, 0);
selection.$moveSelection(function() {
selection.moveCursorTo(rows.first+linesMoved, 0);
});
};
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();
};
this.getFirstVisibleRow = function() {
return this.windowModel.getFirstVisibleRow();
};
this.getLastVisibleRow = function() {
return this.windowModel.getLastVisibleRow();
};
this.isRowVisible = function(row) {
return this.windowModel.isRowVisible(row);
};
this.$getVisibleRowCount = function() {
return this.windowModel.getVisibleRowCount();
};
this.$getPageDownRow = function() {
return this.windowModel.getPageDownRow();
};
this.$getPageUpRow = function() {
return this.windowModel.getPageUpRow();
};
this.selectPageDown = function() {
var row = this.$getPageDownRow() + Math.floor(this.$getVisibleRowCount() / 2);
this.scrollPageDown();
var selection = this.getSelection();
var leadScreenPos = this.session.documentToScreenPosition(selection.getSelectionLead());
var dest = this.session.screenToDocumentPosition(row, leadScreenPos.column);
selection.selectTo(dest.row, dest.column);
};
this.selectPageUp = function() {
var visibleRows = this.windowModel.getScrollTopRow() - this.windowModel.getScrollBottomRow();
var row = this.$getPageUpRow() + Math.round(visibleRows / 2);
this.scrollPageUp();
var selection = this.getSelection();
var leadScreenPos = this.session.documentToScreenPosition(selection.getSelectionLead());
var dest = this.session.screenToDocumentPosition(row, leadScreenPos.column);
selection.selectTo(dest.row, dest.column);
};
this.gotoPageDown = function() {
var row = this.$getPageDownRow();
var column = this.getCursorPositionScreen().column;
this.scrollToRow(row);
this.getSelection().moveCursorToScreen(row, column);
};
this.gotoPageUp = function() {
var row = this.$getPageUpRow();
var column = this.getCursorPositionScreen().column;
this.scrollToRow(row);
this.getSelection().moveCursorToScreen(row, column);
};
this.scrollPageDown = function() {
this.scrollToRow(this.$getPageDownRow());
};
this.scrollPageUp = function() {
this.windowModel.scrollToRow(this.$getPageUpRow());
};
this.scrollToRow = function(row) {
this.windowModel.scrollToRow(row);
};
this.scrollToLine = function(line, center) {
this.windowModel.scrollToLine(line, center);
};
this.centerSelection = function() {
this.windowModel.centerSelection();
};
this.getCursorPosition = function() {
return this.windowModel.getCursorPosition();
};
this.getCursorPositionScreen = function() {
return this.windowModel.getCursorPositionScreen();
};
this.getSelectionRange = function() {
return this.windowModel.getSelectionRange();
};
this.selectAll = function() {
this.windowModel.selectAll();
};
this.clearSelection = function() {
this.windowModel.clearSelection();
};
this.moveCursorTo = function(row, column) {
this.windowModel.moveCursorTo(row, column);
};
this.moveCursorToPosition = function(pos) {
this.windowModel.moveCursorToPosition(pos);
};
this.gotoLine = function(lineNumber, column) {
this.windowModel.gotoLine(lineNumber, column);
};
this.navigateTo = function(row, column) {
this.windowModel.navigateTo(row, column);
};
this.navigateUp = function(times) {
this.windowModel.navigateUp(times);
};
this.navigateDown = function(times) {
this.windowModel.navigateDown(times);
};
this.navigateLeft = function(times) {
this.windowModel.navigateLeft(times);
};
this.navigateRight = function(times) {
this.windowModel.navigateRight(times);
};
this.navigateLineStart = function() {
this.windowModel.navigateLineStart()
};
this.navigateLineEnd = function() {
this.windowModel.navigateLineEnd();
};
this.navigateFileEnd = function() {
this.windowModel.navigateFileEnd();
};
this.navigateFileStart = function() {
this.windowModel.navigateFileStart();
};
this.navigateWordRight = function() {
this.windowModel.navigateWordRight();
};
this.navigateWordLeft = function() {
this.windowModel.navigateWordLeft();
};
this.replace = function(replacement, options) {
this.windowModel.replace(replace, options);
};
this.replaceAll = function(replacement, options) {
this.windowModel.replaceAll(replaceAll, options);
};
this.getLastSearchOptions = function() {
return this.windowModel.getLastSearchOptions();
};
this.find = function(needle, options) {
this.windowModel.find(needle, options);
};
this.findNext = function(options) {
this.windowModel.findNext(options);
};
this.findPrevious = function(options) {
this.windowModel.findPrevious(options);
};
this.undo = function() {
this.session.getUndoManager().undo();
};
this.redo = function() {
this.session.getUndoManager().redo();
};
this.destroy = function() {
this.renderer.destroy();
}
}).call(Editor.prototype);
exports.Editor = Editor;
});

View file

@ -1,53 +1,58 @@
/* ***** BEGIN LICENSE BLOCK ***** /* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
* *
* Copyright (c) 2010, Ajax.org B.V. * The contents of this file are subject to the Mozilla Public License Version
* All rights reserved. * 1.1 (the "License"); you may not use this file except in compliance with
* * the License. You may obtain a copy of the License at
* Redistribution and use in source and binary forms, with or without * http://www.mozilla.org/MPL/
* modification, are permitted provided that the following conditions are met: *
* * Redistributions of source code must retain the above copyright * Software distributed under the License is distributed on an "AS IS" basis,
* notice, this list of conditions and the following disclaimer. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* * Redistributions in binary form must reproduce the above copyright * for the specific language governing rights and limitations under the
* notice, this list of conditions and the following disclaimer in the * License.
* documentation and/or other materials provided with the distribution. *
* * Neither the name of Ajax.org B.V. nor the * The Original Code is Ajax.org Code Editor (ACE).
* names of its contributors may be used to endorse or promote products *
* derived from this software without specific prior written permission. * The Initial Developer of the Original Code is
* * Ajax.org B.V.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * Portions created by the Initial Developer are Copyright (C) 2010
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * the Initial Developer. All Rights Reserved.
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY * Contributor(s):
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * Fabian Jakobs <fabian AT ajax DOT org>
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; *
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * Alternatively, the contents of this file may be used under the terms of
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * either the GNU General Public License Version 2 or later (the "GPL"), or
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
* *
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
if (typeof process !== "undefined") { if (typeof process !== "undefined") {
require("amd-loader"); require("../support/paths");
require("./test/mockdom"); require("ace/test/mockdom");
} }
define(function(require, exports, module) { define(function(require, exports, module) {
"use strict";
var EditSession = require("./edit_session").EditSession; var Buffer = require("ace/model/buffer").Buffer;
var Editor = require("./editor").Editor; var Editor = require("ace/editor").Editor;
var JavaScriptMode = require("./mode/javascript").Mode; var JavaScriptMode = require("ace/mode/javascript").Mode;
var UndoManager = require("./undomanager").UndoManager; var UndoManager = require("ace/undomanager").UndoManager;
var MockRenderer = require("./test/mockrenderer").MockRenderer; var WindowViewMock = require("ace/view/window_view_mock").WindowViewMock;
var assert = require("./test/assertions"); var assert = require("ace/test/assertions");
var whitespace = require("./ext/whitespace");
module.exports = { module.exports = {
"test: delete line from the middle" : function() { "test: delete line from the middle" : function() {
var session = new EditSession(["a", "b", "c", "d"].join("\n")); var session = new Buffer(["a", "b", "c", "d"].join("\n"));
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(1, 1); editor.moveCursorTo(1, 1);
editor.removeLines(); editor.removeLines();
@ -72,8 +77,8 @@ module.exports = {
}, },
"test: delete multiple selected lines" : function() { "test: delete multiple selected lines" : function() {
var session = new EditSession(["a", "b", "c", "d"].join("\n")); var session = new Buffer(["a", "b", "c", "d"].join("\n"));
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(1, 1); editor.moveCursorTo(1, 1);
editor.getSelection().selectDown(); editor.getSelection().selectDown();
@ -84,8 +89,8 @@ module.exports = {
}, },
"test: delete first line" : function() { "test: delete first line" : function() {
var session = new EditSession(["a", "b", "c"].join("\n")); var session = new Buffer(["a", "b", "c"].join("\n"));
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.removeLines(); editor.removeLines();
@ -94,8 +99,8 @@ module.exports = {
}, },
"test: delete last should also delete the new line of the previous line" : function() { "test: delete last should also delete the new line of the previous line" : function() {
var session = new EditSession(["a", "b", "c", ""].join("\n")); var session = new Buffer(["a", "b", "c", ""].join("\n"));
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(3, 0); editor.moveCursorTo(3, 0);
@ -109,8 +114,8 @@ module.exports = {
}, },
"test: indent block" : function() { "test: indent block" : function() {
var session = new EditSession(["a12345", "b12345", "c12345"].join("\n")); var session = new Buffer(["a12345", "b12345", "c12345"].join("\n"));
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(1, 3); editor.moveCursorTo(1, 3);
editor.getSelection().selectDown(); editor.getSelection().selectDown();
@ -127,8 +132,8 @@ module.exports = {
}, },
"test: indent selected lines" : function() { "test: indent selected lines" : function() {
var session = new EditSession(["a12345", "b12345", "c12345"].join("\n")); var session = new Buffer(["a12345", "b12345", "c12345"].join("\n"));
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(1, 0); editor.moveCursorTo(1, 0);
editor.getSelection().selectDown(); editor.getSelection().selectDown();
@ -138,17 +143,17 @@ module.exports = {
}, },
"test: no auto indent if cursor is before the {" : function() { "test: no auto indent if cursor is before the {" : function() {
var session = new EditSession("{", new JavaScriptMode()); var session = new Buffer("{", new JavaScriptMode());
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(0, 0); editor.moveCursorTo(0, 0);
editor.onTextInput("\n"); editor.onTextInput("\n");
assert.equal(["", "{"].join("\n"), session.toString()); assert.equal(["", "{"].join("\n"), session.toString());
}, },
"test: outdent block" : function() { "test: outdent block" : function() {
var session = new EditSession([" a12345", " b12345", " c12345"].join("\n")); var session = new Buffer([" a12345", " b12345", " c12345"].join("\n"));
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(0, 5); editor.moveCursorTo(0, 5);
editor.getSelection().selectDown(); editor.getSelection().selectDown();
@ -172,8 +177,8 @@ module.exports = {
}, },
"test: outent without a selection should update cursor" : function() { "test: outent without a selection should update cursor" : function() {
var session = new EditSession(" 12"); var session = new Buffer(" 12");
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(0, 3); editor.moveCursorTo(0, 3);
editor.blockOutdent(" "); editor.blockOutdent(" ");
@ -183,25 +188,23 @@ module.exports = {
}, },
"test: comment lines should perserve selection" : function() { "test: comment lines should perserve selection" : function() {
var session = new EditSession([" abc", "cde"].join("\n"), new JavaScriptMode()); var session = new Buffer([" abc", "cde"].join("\n"), new JavaScriptMode());
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
whitespace.detectIndentation(session);
editor.moveCursorTo(0, 2); editor.moveCursorTo(0, 2);
editor.getSelection().selectDown(); editor.getSelection().selectDown();
editor.toggleCommentLines(); editor.toggleCommentLines();
assert.equal(["// abc", "// cde"].join("\n"), session.toString()); assert.equal(["// abc", "//cde"].join("\n"), session.toString());
var selection = editor.getSelectionRange(); var selection = editor.getSelectionRange();
assert.position(selection.start, 0, 5); assert.position(selection.start, 0, 4);
assert.position(selection.end, 1, 5); assert.position(selection.end, 1, 4);
}, },
"test: uncomment lines should perserve selection" : function() { "test: uncomment lines should perserve selection" : function() {
var session = new EditSession(["// abc", "//cde"].join("\n"), new JavaScriptMode()); var session = new Buffer(["// abc", "//cde"].join("\n"), new JavaScriptMode());
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
session.setTabSize(2);
editor.moveCursorTo(0, 1); editor.moveCursorTo(0, 1);
editor.getSelection().selectDown(); editor.getSelection().selectDown();
@ -215,8 +218,8 @@ module.exports = {
}, },
"test: toggle comment lines twice should return the original text" : function() { "test: toggle comment lines twice should return the original text" : function() {
var session = new EditSession([" abc", "cde", "fg"], new JavaScriptMode()); var session = new Buffer([" abc", "cde", "fg"], new JavaScriptMode());
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(0, 0); editor.moveCursorTo(0, 0);
editor.getSelection().selectDown(); editor.getSelection().selectDown();
@ -231,94 +234,95 @@ module.exports = {
"test: comment lines - if the selection end is at the line start it should stay there": function() { "test: comment lines - if the selection end is at the line start it should stay there": function() {
//select down //select down
var session = new EditSession(["abc", "cde"].join("\n"), new JavaScriptMode()); var session = new Buffer(["abc", "cde"].join("\n"), new JavaScriptMode());
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(0, 0); editor.moveCursorTo(0, 0);
editor.getSelection().selectDown(); editor.getSelection().selectDown();
editor.toggleCommentLines(); editor.toggleCommentLines();
assert.range(editor.getSelectionRange(), 0, 3, 1, 0); assert.range(editor.getSelectionRange(), 0, 2, 1, 0);
// select up // select up
var session = new EditSession(["abc", "cde"].join("\n"), new JavaScriptMode()); var session = new Buffer(["abc", "cde"].join("\n"), new JavaScriptMode());
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(1, 0); editor.moveCursorTo(1, 0);
editor.getSelection().selectUp(); editor.getSelection().selectUp();
editor.toggleCommentLines(); editor.toggleCommentLines();
assert.range(editor.getSelectionRange(), 0, 3, 1, 0); assert.range(editor.getSelectionRange(), 0, 2, 1, 0);
}, },
"test: move lines down should keep selection on moved lines" : function() { "test: move lines down should select moved lines" : function() {
var session = new EditSession(["11", "22", "33", "44"].join("\n")); var session = new Buffer(["11", "22", "33", "44"].join("\n"));
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(0, 1); editor.moveCursorTo(0, 1);
editor.getSelection().selectDown(); editor.getSelection().selectDown();
editor.moveLinesDown(); editor.moveLinesDown();
assert.equal(["33", "11", "22", "44"].join("\n"), session.toString()); assert.equal(["33", "11", "22", "44"].join("\n"), session.toString());
assert.position(editor.getCursorPosition(), 2, 1); assert.position(editor.getCursorPosition(), 1, 0);
assert.position(editor.getSelection().getSelectionAnchor(), 1, 1); assert.position(editor.getSelection().getSelectionAnchor(), 3, 0);
assert.position(editor.getSelection().getSelectionLead(), 2, 1); assert.position(editor.getSelection().getSelectionLead(), 1, 0);
editor.moveLinesDown(); editor.moveLinesDown();
assert.equal(["33", "44", "11", "22"].join("\n"), session.toString()); assert.equal(["33", "44", "11", "22"].join("\n"), session.toString());
assert.position(editor.getCursorPosition(), 3, 1); assert.position(editor.getCursorPosition(), 2, 0);
assert.position(editor.getSelection().getSelectionAnchor(), 2, 1); assert.position(editor.getSelection().getSelectionAnchor(), 3, 2);
assert.position(editor.getSelection().getSelectionLead(), 3, 1); assert.position(editor.getSelection().getSelectionLead(), 2, 0);
// moving again should have no effect // moving again should have no effect
editor.moveLinesDown(); editor.moveLinesDown();
assert.equal(["33", "44", "11", "22"].join("\n"), session.toString()); assert.equal(["33", "44", "11", "22"].join("\n"), session.toString());
assert.position(editor.getCursorPosition(), 3, 1); assert.position(editor.getCursorPosition(), 2, 0);
assert.position(editor.getSelection().getSelectionAnchor(), 2, 1); assert.position(editor.getSelection().getSelectionAnchor(), 3, 2);
assert.position(editor.getSelection().getSelectionLead(), 3, 1); assert.position(editor.getSelection().getSelectionLead(), 2, 0);
}, },
"test: move lines up should keep selection on moved lines" : function() { "test: move lines up should select moved lines" : function() {
var session = new EditSession(["11", "22", "33", "44"].join("\n")); var session = new Buffer(["11", "22", "33", "44"].join("\n"));
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(2, 1); editor.moveCursorTo(2, 1);
editor.getSelection().selectDown(); editor.getSelection().selectDown();
editor.moveLinesUp(); editor.moveLinesUp();
assert.equal(session.toString(), ["11", "33", "44", "22"].join("\n")); assert.equal(session.toString(), ["11", "33", "44", "22"].join("\n"));
assert.position(editor.getCursorPosition(), 2, 1); assert.position(editor.getCursorPosition(), 1, 0);
assert.position(editor.getSelection().getSelectionAnchor(), 1, 1); assert.position(editor.getSelection().getSelectionAnchor(), 3, 0);
assert.position(editor.getSelection().getSelectionLead(), 2, 1); assert.position(editor.getSelection().getSelectionLead(), 1, 0);
editor.moveLinesUp(); editor.moveLinesUp();
assert.equal(session.toString(), ["33", "44", "11", "22"].join("\n")); assert.equal(session.toString(), ["33", "44", "11", "22"].join("\n"));
assert.position(editor.getCursorPosition(), 1, 1); assert.position(editor.getCursorPosition(), 0, 0);
assert.position(editor.getSelection().getSelectionAnchor(), 0, 1); assert.position(editor.getSelection().getSelectionAnchor(), 2, 0);
assert.position(editor.getSelection().getSelectionLead(), 1, 1); assert.position(editor.getSelection().getSelectionLead(), 0, 0);
}, },
"test: move line without active selection should not move cursor relative to the moved line" : function() { "test: move line without active selection should move cursor to start of the moved line" : function()
var session = new EditSession(["11", "22", "33", "44"].join("\n")); {
var editor = new Editor(new MockRenderer(), session); var session = new Buffer(["11", "22", "33", "44"].join("\n"));
var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(1, 1); editor.moveCursorTo(1, 1);
editor.clearSelection(); editor.clearSelection();
editor.moveLinesDown(); editor.moveLinesDown();
assert.equal(["11", "33", "22", "44"].join("\n"), session.toString()); assert.equal(["11", "33", "22", "44"].join("\n"), session.toString());
assert.position(editor.getCursorPosition(), 2, 1); assert.position(editor.getCursorPosition(), 2, 0);
editor.clearSelection(); editor.clearSelection();
editor.moveLinesUp(); editor.moveLinesUp();
assert.equal(["11", "22", "33", "44"].join("\n"), session.toString()); assert.equal(["11", "22", "33", "44"].join("\n"), session.toString());
assert.position(editor.getCursorPosition(), 1, 1); assert.position(editor.getCursorPosition(), 1, 0);
}, },
"test: copy lines down should keep selection" : function() { "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 session = new Buffer(["11", "22", "33", "44"].join("\n"));
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(1, 1); editor.moveCursorTo(1, 1);
editor.getSelection().selectDown(); editor.getSelection().selectDown();
@ -326,14 +330,14 @@ module.exports = {
editor.copyLinesDown(); editor.copyLinesDown();
assert.equal(["11", "22", "33", "22", "33", "44"].join("\n"), session.toString()); assert.equal(["11", "22", "33", "22", "33", "44"].join("\n"), session.toString());
assert.position(editor.getCursorPosition(), 4, 1); assert.position(editor.getCursorPosition(), 3, 0);
assert.position(editor.getSelection().getSelectionAnchor(), 3, 1); assert.position(editor.getSelection().getSelectionAnchor(), 5, 0);
assert.position(editor.getSelection().getSelectionLead(), 4, 1); assert.position(editor.getSelection().getSelectionLead(), 3, 0);
}, },
"test: copy lines up should keep selection" : function() { "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 session = new Buffer(["11", "22", "33", "44"].join("\n"));
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(1, 1); editor.moveCursorTo(1, 1);
editor.getSelection().selectDown(); editor.getSelection().selectDown();
@ -341,14 +345,14 @@ module.exports = {
editor.copyLinesUp(); editor.copyLinesUp();
assert.equal(["11", "22", "33", "22", "33", "44"].join("\n"), session.toString()); assert.equal(["11", "22", "33", "22", "33", "44"].join("\n"), session.toString());
assert.position(editor.getCursorPosition(), 2, 1); assert.position(editor.getCursorPosition(), 1, 0);
assert.position(editor.getSelection().getSelectionAnchor(), 1, 1); assert.position(editor.getSelection().getSelectionAnchor(), 3, 0);
assert.position(editor.getSelection().getSelectionLead(), 2, 1); assert.position(editor.getSelection().getSelectionLead(), 1, 0);
}, },
"test: input a tab with soft tab should convert it to spaces" : function() { "test: input a tab with soft tab should convert it to spaces" : function() {
var session = new EditSession(""); var session = new Buffer("");
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
session.setTabSize(2); session.setTabSize(2);
session.setUseSoftTabs(true); session.setUseSoftTabs(true);
@ -362,8 +366,8 @@ module.exports = {
}, },
"test: input tab without soft tabs should keep the tab character" : function() { "test: input tab without soft tabs should keep the tab character" : function() {
var session = new EditSession(""); var session = new Buffer("");
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
session.setUseSoftTabs(false); session.setUseSoftTabs(false);
@ -372,12 +376,12 @@ module.exports = {
}, },
"test: undo/redo for delete line" : function() { "test: undo/redo for delete line" : function() {
var session = new EditSession(["111", "222", "333"]); var session = new Buffer(["111", "222", "333"]);
var undoManager = new UndoManager(); var undoManager = new UndoManager();
session.setUndoManager(undoManager); session.setUndoManager(undoManager);
var initialText = session.toString(); var initialText = session.toString();
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.removeLines(); editor.removeLines();
var step1 = session.toString(); var step1 = session.toString();
@ -412,38 +416,38 @@ module.exports = {
}, },
"test: remove left should remove character left of the cursor" : function() { "test: remove left should remove character left of the cursor" : function() {
var session = new EditSession(["123", "456"]); var session = new Buffer(["123", "456"]);
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(1, 1); editor.moveCursorTo(1, 1);
editor.remove("left"); editor.removeLeft();
assert.equal(session.toString(), "123\n56"); assert.equal(session.toString(), "123\n56");
}, },
"test: remove left should remove line break if cursor is at line start" : function() { "test: remove left should remove line break if cursor is at line start" : function() {
var session = new EditSession(["123", "456"]); var session = new Buffer(["123", "456"]);
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(1, 0); editor.moveCursorTo(1, 0);
editor.remove("left"); editor.removeLeft();
assert.equal(session.toString(), "123456"); assert.equal(session.toString(), "123456");
}, },
"test: remove left should remove tabsize spaces if cursor is on a tab stop and preceeded by spaces" : function() { "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"]); var session = new Buffer(["123", " 456"]);
session.setUseSoftTabs(true); session.setUseSoftTabs(true);
session.setTabSize(4); session.setTabSize(4);
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(1, 8); editor.moveCursorTo(1, 8);
editor.remove("left"); editor.removeLeft();
assert.equal(session.toString(), "123\n 456"); assert.equal(session.toString(), "123\n 456");
}, },
"test: transpose at line start should be a noop": function() { "test: transpose at line start should be a noop": function() {
var session = new EditSession(["123", "4567", "89"]); var session = new Buffer(["123", "4567", "89"]);
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(1, 0); editor.moveCursorTo(1, 0);
editor.transposeLetters(); editor.transposeLetters();
@ -451,9 +455,9 @@ module.exports = {
}, },
"test: transpose in line should swap the charaters before and after the cursor": function() { "test: transpose in line should swap the charaters before and after the cursor": function() {
var session = new EditSession(["123", "4567", "89"]); var session = new Buffer(["123", "4567", "89"]);
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(1, 2); editor.moveCursorTo(1, 2);
editor.transposeLetters(); editor.transposeLetters();
@ -461,9 +465,9 @@ module.exports = {
}, },
"test: transpose at line end should swap the last two characters": function() { "test: transpose at line end should swap the last two characters": function() {
var session = new EditSession(["123", "4567", "89"]); var session = new Buffer(["123", "4567", "89"]);
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(1, 4); editor.moveCursorTo(1, 4);
editor.transposeLetters(); editor.transposeLetters();
@ -471,9 +475,9 @@ module.exports = {
}, },
"test: transpose with non empty selection should be a noop": function() { "test: transpose with non empty selection should be a noop": function() {
var session = new EditSession(["123", "4567", "89"]); var session = new Buffer(["123", "4567", "89"]);
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(1, 1); editor.moveCursorTo(1, 1);
editor.getSelection().selectRight(); editor.getSelection().selectRight();
editor.transposeLetters(); editor.transposeLetters();
@ -482,71 +486,31 @@ module.exports = {
}, },
"test: transpose should move the cursor behind the last swapped character": function() { "test: transpose should move the cursor behind the last swapped character": function() {
var session = new EditSession(["123", "4567", "89"]); var session = new Buffer(["123", "4567", "89"]);
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(1, 2); editor.moveCursorTo(1, 2);
editor.transposeLetters(); editor.transposeLetters();
assert.position(editor.getCursorPosition(), 1, 3); assert.position(editor.getCursorPosition(), 1, 3);
}, },
"test: remove to line end": function() { "test: remove to line end": function() {
var session = new EditSession(["123", "4567", "89"]); var session = new Buffer(["123", "4567", "89"]);
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(1, 2); editor.moveCursorTo(1, 2);
editor.removeToLineEnd(); editor.removeToLineEnd();
assert.equal(session.getValue(), ["123", "45", "89"].join("\n")); assert.equal(session.getValue(), ["123", "45", "89"].join("\n"));
}, },
"test: remove to line end at line end should remove the new line": function() { "test: remove to line end at line end should remove the new line": function() {
var session = new EditSession(["123", "4567", "89"]); var session = new Buffer(["123", "4567", "89"]);
var editor = new Editor(new MockRenderer(), session); var editor = new Editor(new WindowViewMock(), session);
editor.moveCursorTo(1, 4); editor.moveCursorTo(1, 4);
editor.removeToLineEnd(); editor.removeToLineEnd();
assert.position(editor.getCursorPosition(), 1, 4); assert.position(editor.getCursorPosition(), 1, 4);
assert.equal(session.getValue(), ["123", "456789"].join("\n")); 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);
} }
}; };
@ -554,4 +518,4 @@ module.exports = {
if (typeof module !== "undefined" && module === require.main) { if (typeof module !== "undefined" && module === require.main) {
require("asyncjs").test.testcase(module.exports).exec() require("asyncjs").test.testcase(module.exports).exec()
} }

View file

@ -0,0 +1,116 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Skywriter.
*
* The Initial Developer of the Original Code is
* Mozilla.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Julian Viereck (julian.viereck@gmail.com)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var keyUtil = require("ace/lib/keys");
function HashHandler(config) {
this.setConfig(config);
}
(function() {
function splitSafe(s, separator, limit, bLowerCase) {
return (bLowerCase && s.toLowerCase() || s)
.replace(/(?:^\s+|\n|\s+$)/g, "")
.split(new RegExp("[\\s ]*" + separator + "[\\s ]*", "g"), limit || 999);
}
function parseKeys(keys, val, ret) {
var key,
hashId = 0,
parts = splitSafe(keys, "\\-", null, true),
i = 0,
l = parts.length;
for (; i < l; ++i) {
if (keyUtil.KEY_MODS[parts[i]])
hashId = hashId | keyUtil.KEY_MODS[parts[i]];
else
key = parts[i] || "-"; //when empty, the splitSafe removed a '-'
}
(ret[hashId] || (ret[hashId] = {}))[key] = val;
return ret;
}
function objectReverse(obj, keySplit) {
var i, j, l, key,
ret = {};
for (i in obj) {
key = obj[i];
if (keySplit && typeof key == "string") {
key = key.split(keySplit);
for (j = 0, l = key.length; j < l; ++j)
parseKeys.call(this, key[j], i, ret);
}
else {
parseKeys.call(this, key, i, ret);
}
}
return ret;
}
this.setConfig = function(config) {
this.$config = config;
if (typeof this.$config.reverse == "undefined")
this.$config.reverse = objectReverse.call(this, this.$config, "|");
};
/**
* This function is called by keyBinding.
*/
this.handleKeyboard = function(data, hashId, textOrKey, keyCode) {
// Figure out if a commandKey was pressed or just some text was insert.
if (hashId != 0 || keyCode != 0) {
return {
command: (this.$config.reverse[hashId] || {})[textOrKey]
}
} else {
return {
command: "inserttext",
args: {
text: textOrKey
}
}
}
}
}).call(HashHandler.prototype)
exports.HashHandler = HashHandler;
});

119
ace/keyboard/keybinding.js Normal file
View file

@ -0,0 +1,119 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Julian Viereck <julian.viereck@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var useragent = require("ace/lib/useragent");
var keyUtil = require("ace/lib/keys");
var event = require("ace/lib/event");
require("ace/commands/default_commands");
var KeyBinding = function(editor) {
this.$editor = editor;
this.$data = { };
this.$keyboardHandler = null;
};
(function() {
this.setKeyboardHandler = function(keyboardHandler) {
if (this.$keyboardHandler != keyboardHandler) {
this.$data = { };
this.$keyboardHandler = keyboardHandler;
}
};
this.getKeyboardHandler = function() {
return this.$keyboardHandler;
};
this.$callKeyboardHandler = function (e, hashId, keyOrText, keyCode) {
var env = {editor: this.$editor};
var toExecute;
var commands = this.$editor.commands;
if (this.$keyboardHandler) {
toExecute =
this.$keyboardHandler.handleKeyboard(this.$data, hashId, keyOrText, keyCode, e);
}
// If there is nothing to execute yet, then use the default keymapping.
if (!toExecute || !toExecute.command) {
if (hashId != 0 || keyCode != 0) {
toExecute = {
command: commands.findKeyCommand(env, hashId, keyOrText)
}
} else {
toExecute = {
command: "inserttext",
args: {
text: keyOrText
}
}
}
}
var success = false;
if (toExecute && toExecute.command) {
success = commands.exec(
toExecute.command,
env, toExecute.args
);
if (success) {
event.stopEvent(e);
}
}
return success;
};
this.onCommandKey = function(e, hashId, keyCode, keyString) {
// In case there is no keyString, try to interprete the keyCode.
if (!keyString) {
keyString = keyUtil.keyCodeToString(keyCode);
}
return this.$callKeyboardHandler(e, hashId, keyString, keyCode);
};
this.onTextInput = function(text) {
return this.$callKeyboardHandler({}, 0, text, 0);
}
}).call(KeyBinding.prototype);
exports.KeyBinding = KeyBinding;
});

View file

@ -0,0 +1,149 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Skywriter.
*
* The Initial Developer of the Original Code is
* Mozilla.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Julian Viereck (julian.viereck@gmail.com)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var StateHandler = require("ace/keyboard/state_handler").StateHandler;
var matchCharacterOnly = require("ace/keyboard/state_handler").matchCharacterOnly;
var emacsState = {
start: [
{
key: "ctrl-x",
then: "c-x"
},
{
regex: [ "(?:command-([0-9]*))*", "(down|ctrl-n)" ],
exec: "golinedown",
params: [
{
name: "times",
match: 1,
type: "number",
defaultValue: 1
}
]
},
{
regex: [ "(?:command-([0-9]*))*", "(right|ctrl-f)" ],
exec: "gotoright",
params: [
{
name: "times",
match: 1,
type: "number",
defaultValue: 1
}
]
},
{
regex: [ "(?:command-([0-9]*))*", "(up|ctrl-p)" ],
exec: "golineup",
params: [
{
name: "times",
match: 1,
type: "number",
defaultValue: 1
}
]
},
{
regex: [ "(?:command-([0-9]*))*", "(left|ctrl-b)" ],
exec: "gotoleft",
params: [
{
name: "times",
match: 1,
type: "number",
defaultValue: 1
}
]
},
{
comment: "This binding matches all printable characters except numbers as long as they are no numbers and print them n times.",
regex: [ "(?:command-([0-9]*))", "([^0-9]+)*" ],
match: matchCharacterOnly,
exec: "inserttext",
params: [
{
name: "times",
match: 1,
type: "number",
defaultValue: "1"
},
{
name: "text",
match: 2
}
]
},
{
comment: "This binding matches numbers as long as there is no meta_number in the buffer.",
regex: [ "(command-[0-9]*)*", "([0-9]+)" ],
match: matchCharacterOnly,
disallowMatches: [ 1 ],
exec: "inserttext",
params: [
{
name: "text",
match: 2,
type: "text"
}
]
},
{
regex: [ "command-([0-9]*)", "(command-[0-9]|[0-9])" ],
comment: "Stops execution if the regex /meta_[0-9]+/ matches to avoid resetting the buffer."
}
],
"c-x": [
{
key: "ctrl-g",
then: "start"
},
{
key: "ctrl-s",
exec: "save",
then: "start"
}
]
};
exports.Emacs = new StateHandler(emacsState);
});

View file

@ -0,0 +1,179 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Skywriter.
*
* The Initial Developer of the Original Code is
* Mozilla.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Julian Viereck (julian.viereck@gmail.com)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var StateHandler = require("ace/keyboard/state_handler").StateHandler;
var matchCharacterOnly = require("ace/keyboard/state_handler").matchCharacterOnly;
var vimStates = {
start: [
{
key: "i",
then: "insertMode"
},
{
key: "d",
then: "deleteMode"
},
{
key: "a",
exec: "gotoright",
then: "insertMode"
},
{
key: "shift-i",
exec: "gotolinestart",
then: "insertMode"
},
{
key: "shift-a",
exec: "gotolineend",
then: "insertMode"
},
{
key: "shift-c",
exec: "removetolineend",
then: "insertMode"
},
{
key: "shift-r",
exec: "overwrite",
then: "replaceMode"
},
{
regex: [ "([0-9]*)", "(k|up)" ],
exec: "golineup",
params: [
{
name: "times",
match: 1,
type: "number",
defaultValue: 1
}
]
},
{
regex: [ "([0-9]*)", "(j|down|enter)" ],
exec: "golinedown",
params: [
{
name: "times",
match: 1,
type: "number",
defaultValue: 1
}
]
},
{
regex: [ "([0-9]*)", "(l|right)" ],
exec: "gotoright",
params: [
{
name: "times",
match: 1,
type: "number",
defaultValue: 1
}
]
},
{
regex: [ "([0-9]*)", "(h|left)" ],
exec: "gotoleft",
params: [
{
name: "times",
match: 1,
type: "number",
defaultValue: 1
}
]
},
{
key: "shift-g",
exec: "gotoend"
},
{
key: "b",
exec: "gotowordleft"
},
{
key: "e",
exec: "gotowordright"
},
{
key: "x",
exec: "del"
},
{
key: "shift-x",
exec: "backspace"
},
{
key: "shift-d",
exec: "removetolineend"
},
{
comment: "Catch some keyboard input to stop it here",
match: matchCharacterOnly
}
],
insertMode: [
{
key: "esc",
then: "start"
}
],
replaceMode: [
{
key: "esc",
exec: "overwrite",
then: "start"
}
],
deleteMode: [
{
key: "d",
exec: "removeline",
then: "start"
}
]
};
exports.Vim = new StateHandler(vimStates);
});

View file

@ -1,35 +1,41 @@
/* ***** BEGIN LICENSE BLOCK ***** /* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
* *
* Copyright (c) 2010, Ajax.org B.V. * The contents of this file are subject to the Mozilla Public License Version
* All rights reserved. * 1.1 (the "License"); you may not use this file except in compliance with
* * the License. You may obtain a copy of the License at
* Redistribution and use in source and binary forms, with or without * http://www.mozilla.org/MPL/
* modification, are permitted provided that the following conditions are met: *
* * Redistributions of source code must retain the above copyright * Software distributed under the License is distributed on an "AS IS" basis,
* notice, this list of conditions and the following disclaimer. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* * Redistributions in binary form must reproduce the above copyright * for the specific language governing rights and limitations under the
* notice, this list of conditions and the following disclaimer in the * License.
* documentation and/or other materials provided with the distribution. *
* * Neither the name of Ajax.org B.V. nor the * The Original Code is Mozilla Skywriter.
* names of its contributors may be used to endorse or promote products *
* derived from this software without specific prior written permission. * The Initial Developer of the Original Code is
* * Mozilla.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * Portions created by the Initial Developer are Copyright (C) 2009
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * the Initial Developer. All Rights Reserved.
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY * Contributor(s):
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * Julian Viereck (julian.viereck@gmail.com)
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; *
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * Alternatively, the contents of this file may be used under the terms of
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * either the GNU General Public License Version 2 or later (the "GPL"), or
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
* *
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) { define(function(require, exports, module) {
"use strict";
// If you're developing a new keymapping and want to get an idea what's going // If you're developing a new keymapping and want to get an idea what's going
// on, then enable debugging. // on, then enable debugging.
@ -40,13 +46,13 @@ function StateHandler(keymapping) {
} }
StateHandler.prototype = { StateHandler.prototype = {
/* /**
* Build the RegExp from the keymapping as RegExp can't stored directly * 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 * in the metadata JSON and as the RegExp used to match the keys/buffer
* need to be adapted. * need to be adapted.
*/ */
$buildKeymappingRegex: function(keymapping) { $buildKeymappingRegex: function(keymapping) {
for (var state in keymapping) { for (state in keymapping) {
this.$buildBindingsRegex(keymapping[state]); this.$buildBindingsRegex(keymapping[state]);
} }
return keymapping; return keymapping;
@ -58,8 +64,7 @@ StateHandler.prototype = {
if (binding.key) { if (binding.key) {
binding.key = new RegExp('^' + binding.key + '$'); binding.key = new RegExp('^' + binding.key + '$');
} else if (Array.isArray(binding.regex)) { } else if (Array.isArray(binding.regex)) {
if (!('key' in binding)) binding.key = new RegExp('^' + binding.regex[1] + '$');
binding.key = new RegExp('^' + binding.regex[1] + '$');
binding.regex = new RegExp(binding.regex.join('') + '$'); binding.regex = new RegExp(binding.regex.join('') + '$');
} else if (binding.regex) { } else if (binding.regex) {
binding.regex = new RegExp(binding.regex + '$'); binding.regex = new RegExp(binding.regex + '$');
@ -67,7 +72,7 @@ StateHandler.prototype = {
}); });
}, },
$composeBuffer: function(data, hashId, key, e) { $composeBuffer: function(data, hashId, key) {
// Initialize the data object. // Initialize the data object.
if (data.state == null || data.buffer == null) { if (data.state == null || data.buffer == null) {
data.state = "start"; data.state = "start";
@ -96,23 +101,17 @@ StateHandler.prototype = {
data.buffer = bufferToUse; data.buffer = bufferToUse;
} }
var bufferObj = { return {
bufferToUse: bufferToUse, bufferToUse: bufferToUse,
symbolicName: symbolicName symbolicName: symbolicName
}; };
if (e) {
bufferObj.keyIdentifier = e.keyIdentifier;
}
return bufferObj;
}, },
$find: function(data, buffer, symbolicName, hashId, key, keyIdentifier) { $find: function(data, buffer, symbolicName, hashId, key) {
// Holds the command to execute and the args if a command matched. // Holds the command to execute and the args if a command matched.
var result = {}; var result = {};
// Loop over all the bindings of the keymap until a match is found. // Loop over all the bindings of the keymapp until a match is found.
this.keymapping[data.state].some(function(binding) { this.keymapping[data.state].some(function(binding) {
var match; var match;
@ -127,7 +126,7 @@ StateHandler.prototype = {
} }
// Check if the match function matches. // Check if the match function matches.
if (binding.match && !binding.match(buffer, hashId, key, symbolicName, keyIdentifier)) { if (binding.match && !binding.match(buffer, hashId, key, symbolicName)) {
return false; return false;
} }
@ -191,26 +190,23 @@ StateHandler.prototype = {
} }
}, },
/* /**
* This function is called by keyBinding. * This function is called by keyBinding.
*/ */
handleKeyboard: function(data, hashId, key, keyCode, e) { handleKeyboard: function(data, hashId, key) {
if (hashId == -1)
hashId = 0
// If we pressed any command key but no other key, then ignore the input. // 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" // Otherwise "shift-" is added to the buffer, and later on "shift-g"
// which results in "shift-shift-g" which doesn't make sense. // which results in "shift-shift-g" which doesn't make senese.
if (hashId != 0 && (key == "" || key == String.fromCharCode(0))) { if (hashId != 0 && (key == "" || key == String.fromCharCode(0))) {
return null; return null;
} }
// Compute the current value of the keyboard input buffer. // Compute the current value of the keyboard input buffer.
var r = this.$composeBuffer(data, hashId, key, e); var r = this.$composeBuffer(data, hashId, key);
var buffer = r.bufferToUse; var buffer = r.bufferToUse;
var symbolicName = r.symbolicName; var symbolicName = r.symbolicName;
var keyId = r.keyIdentifier;
r = this.$find(data, buffer, symbolicName, hashId, key, keyId); r = this.$find(data, buffer, symbolicName, hashId, key);
if (DEBUG) { if (DEBUG) {
console.log("KeyboardStateMapper#match", buffer, symbolicName, r); console.log("KeyboardStateMapper#match", buffer, symbolicName, r);
} }
@ -219,11 +215,12 @@ StateHandler.prototype = {
} }
} }
/* /**
* This is a useful matching function and therefore is defined here so that * This is a useful matching function and therefore is defined here so that
* users of KeyboardStateMapper can use it. * users of KeyboardStateMapper can use it.
* *
* @return {Boolean} If no command key (Command|Option|Shift|Ctrl) is pressed, 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 * returns true. If the only the Shift key is pressed + a character
* true is returned as well. Otherwise, false is returned. * true is returned as well. Otherwise, false is returned.
* Summing up, the function returns true whenever the user typed * Summing up, the function returns true whenever the user typed

272
ace/keyboard/textinput.js Normal file
View file

@ -0,0 +1,272 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Mihai Sucan <mihai DOT sucan AT gmail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var event = require("ace/lib/event");
var useragent = require("ace/lib/useragent");
var dom = require("ace/lib/dom");
var TextInput = function(parentNode, host) {
var text = dom.createElement("textarea");
text.style.left = "-10000px";
parentNode.appendChild(text);
var PLACEHOLDER = String.fromCharCode(0);
sendText();
var inCompostion = false;
var copied = false;
var pasted = false;
var tempStyle = '';
function select() {
try {
text.select();
} catch (e) {}
};
function sendText(valueToSend) {
if (!copied) {
var value = valueToSend || text.value;
if (value) {
if (value.charCodeAt(value.length-1) == PLACEHOLDER.charCodeAt(0))
value = value.slice(0, -1);
if (value) {
if (pasted)
host.onPaste(value);
else
host.onTextInput(value);
}
// If editor is no longer focused we quit immediately, since
// it means that something else is in charge now.
if (!isFocused())
return false;
}
}
copied = false;
pasted = false;
// Safari doesn't fire copy events if no text is selected
text.value = PLACEHOLDER;
select();
}
var onTextInput = function(e) {
setTimeout(function () {
if (!inCompostion)
sendText(e.data);
}, 0);
};
var onPropertyChange = function(e) {
if (useragent.isIE && text.value.charCodeAt(0) > 128) return;
setTimeout(function() {
if (!inCompostion)
sendText();
}, 0);
};
var onCompositionStart = function(e) {
inCompostion = true;
host.onCompositionStart();
if (!useragent.isGecko) 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();
select();
setTimeout(function () {
sendText();
}, 0);
};
var onCut = function(e) {
copied = true;
var copyText = host.getCopyText();
if(copyText) {
text.value = copyText;
host.onCut();
} else
e.preventDefault();
select();
setTimeout(function () {
sendText();
}, 0);
};
event.addCommandKeyListener(text, host.onCommandKey.bind(host));
if (useragent.isIE) {
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();
});
};
if ("onpropertychange" in text && !("oninput" in text))
event.addListener(text, "propertychange", onPropertyChange);
else
event.addListener(text, "input", onTextInput);
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 (useragent.isIE) {
event.addListener(text, "beforecopy", function(e) {
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)
}
});
}
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();
select();
});
this.focus = function() {
host.onFocus();
select();
text.focus();
};
this.blur = function() {
text.blur();
};
function isFocused() {
return document.activeElement === text;
};
this.isFocused = isFocused;
this.getElement = function() {
return text;
};
this.onContextMenu = function(mousePos, isEmpty){
if (mousePos) {
if(!tempStyle)
tempStyle = text.style.cssText;
text.style.cssText = 'position:fixed; z-index:1000;' +
'left:' + (mousePos.x - 2) + 'px; top:' + (mousePos.y - 2) + 'px;'
}
if (isEmpty)
text.value='';
}
this.onContextMenuClose = function(){
setTimeout(function () {
if (tempStyle) {
text.style.cssText = tempStyle;
tempStyle = '';
}
sendText();
}, 0);
}
};
exports.TextInput = TextInput;
});

103
ace/lib/browser_focus.js Normal file
View file

@ -0,0 +1,103 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)
* Julian Viereck <julian.viereck@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var event = require("ace/lib/event");
var EventEmitter = require("ace/lib/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;
});

263
ace/lib/dom.js Normal file
View file

@ -0,0 +1,263 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Mihai Sucan <mihai AT sucan AT gmail ODT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
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;
}
};
if (!document.documentElement.classList) {
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;
};
} else {
exports.hasCssClass = function(el, name) {
return el.classList.contains(name);
};
exports.addCssClass = function(el, name) {
el.classList.add(name);
};
exports.removeCssClass = function(el, name) {
el.classList.remove(name);
};
exports.toggleCssClass = function(el, name) {
return el.classList.toggle(name);
};
}
/**
* Add or remove a CSS class from the list of classes on the given node
* depending on the value of <tt>include</tt>
*/
exports.setCssClass = function(node, className, include) {
if (include) {
exports.addCssClass(node, className);
} else {
exports.removeCssClass(node, className);
}
};
exports.importCssString = function(cssText, doc){
doc = doc || document;
if (doc.createStyleSheet) {
var sheet = doc.createStyleSheet();
sheet.cssText = cssText;
}
else {
var style = doc.createElementNS ?
doc.createElementNS(XHTML_NS, "style") :
doc.createElement("style");
style.appendChild(doc.createTextNode(cssText));
var head = doc.getElementsByTagName("head")[0] || doc.documentElement;
head.appendChild(style);
}
};
exports.getInnerWidth = function(element) {
return (parseInt(exports.computedStyle(element, "paddingLeft"))
+ parseInt(exports.computedStyle(element, "paddingRight")) + element.clientWidth);
};
exports.getInnerHeight = function(element) {
return (parseInt(exports.computedStyle(element, "paddingTop"))
+ parseInt(exports.computedStyle(element, "paddingBottom")) + 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() {
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) {
if (document.body && "textContent" in document.body)
el.textContent = innerText;
else
el.innerText = innerText;
};
exports.getInnerText = function(el) {
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;
};
});

325
ace/lib/event.js Normal file
View file

@ -0,0 +1,325 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var keys = require("ace/lib/keys");
var useragent = require("ace/lib/useragent");
var dom = require("ace/lib/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;
};
exports.getDocumentX = function(e) {
if (e.clientX) {
return e.clientX + dom.getPageScrollLeft();
} else {
return e.pageX;
}
};
exports.getDocumentY = function(e) {
if (e.clientY) {
return e.clientY + dom.getPageScrollTop();
} else {
return e.pageY;
}
};
/**
* @return {Number} 0 for left button, 1 for middle button, 2 for right button
*/
exports.getButton = function(e) {
if (e.type == "dblclick")
return 0;
else if (e.type == "contextmenu")
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) {
function onMouseMove(e) {
eventHandler(e);
return exports.stopPropagation(e);
}
var called = false;
function onReleaseCapture(e) {
eventHandler(e);
if (!called) {
called = true;
releaseCaptureHandler();
}
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 onMouseMove(e) {
eventHandler(e);
e.stopPropagation();
}
function onMouseUp(e) {
eventHandler && eventHandler(e);
releaseCaptureHandler && releaseCaptureHandler();
document.removeEventListener("mousemove", onMouseMove, true);
document.removeEventListener("mouseup", onMouseUp, true);
e.stopPropagation();
}
document.addEventListener("mousemove", onMouseMove, true);
document.addEventListener("mouseup", onMouseUp, true);
};
}
exports.addMouseWheelListener = function(el, callback) {
var max = 0;
var listener = function(e) {
if (e.wheelDelta !== undefined) {
// some versions of Safari (e.g. 5.0.5) report insanely high
// scroll values. These browsers require a higher factor
if (Math.abs(e.wheelDeltaY) > max)
max = Math.abs(e.wheelDeltaY)
if (max > 5000)
factor = 400;
else
factor = 8;
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, button, count, timeout, callback) {
var clicks = 0;
var startX, startY;
var listener = function(e) {
clicks += 1;
if (clicks == 1) {
startX = e.clientX;
startY = e.clientY;
setTimeout(function() {
clicks = 0;
}, timeout || 600);
}
var isButton = exports.getButton(e) == button;
if (!isButton || Math.abs(e.clientX - startX) > 5 || Math.abs(e.clientY - startY) > 5)
clicks = 0;
if (clicks == count) {
clicks = 0;
callback(e);
}
if (isButton)
return exports.preventDefault(e);
};
exports.addListener(el, "mousedown", listener);
useragent.isIE && exports.addListener(el, "dblclick", listener);
};
function normalizeCommandKeys(callback, e, keyCode) {
var hashId = 0;
if (useragent.isOpera && 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 == 0 && !(keyCode in keys.FUNCTION_KEYS)) {
return false;
}
return callback(e, hashId, keyCode);
}
exports.addCommandKeyListener = function(el, callback) {
var addListener = exports.addListener;
if (useragent.isOldGecko) {
// 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);
});
// repeated keys are fired as keypress and not keydown events
if (useragent.isMac && useragent.isOpera) {
addListener(el, "keypress", function(e) {
var keyId = e.keyIdentifier || e.keyCode;
if (lastDown !== keyId) {
return normalizeCommandKeys(callback, e, e.keyCode);
} else {
lastDown = null;
}
});
}
}
};
});

92
ace/lib/event_emitter.js Normal file
View file

@ -0,0 +1,92 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var EventEmitter = {};
EventEmitter._emit =
EventEmitter._dispatchEvent = function(eventName, e) {
this._eventRegistry = this._eventRegistry || {};
var listeners = this._eventRegistry[eventName];
if (!listeners || !listeners.length) return;
var e = e || {};
e.type = eventName;
for (var i=0; i<listeners.length; i++) {
listeners[i](e);
}
};
EventEmitter.on =
EventEmitter.addEventListener = function(eventName, callback) {
this._eventRegistry = this._eventRegistry || {};
var listeners = this._eventRegistry[eventName];
if (!listeners) {
var listeners = this._eventRegistry[eventName] = [];
}
if (listeners.indexOf(callback) == -1) {
listeners.push(callback);
}
};
EventEmitter.removeListener =
EventEmitter.removeEventListener = function(eventName, callback) {
this._eventRegistry = this._eventRegistry || {};
var listeners = this._eventRegistry[eventName];
if (!listeners) {
return;
}
var index = listeners.indexOf(callback);
if (index !== -1) {
listeners.splice(index, 1);
}
};
EventEmitter.removeAllListeners = function(eventName) {
if (this._eventRegistry) this._eventRegistry[eventName] = [];
}
exports.EventEmitter = EventEmitter;
});

840
ace/lib/fixoldbrowsers.js Normal file
View file

@ -0,0 +1,840 @@
// vim:set ts=4 sts=4 sw=4 st:
// -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License
// -- tlrobinson Tom Robinson Copyright (C) 2009-2010 MIT License (Narwhal Project)
// -- dantman Daniel Friesen Copyright(C) 2010 XXX No License Specified
// -- fschaefer Florian Schäfer Copyright (C) 2010 MIT License
// -- Irakli Gozalishvili Copyright (C) 2010 MIT License
/*!
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) {
require("ace/lib/regexp");
/**
* Brings an environment as close to ECMAScript 5 compliance
* as is possible with the facilities of erstwhile engines.
*
* ES5 Draft
* http://www.ecma-international.org/publications/files/drafts/tc39-2009-050.pdf
*
* NOTE: this is a draft, and as such, the URL is subject to change. If the
* link is broken, check in the parent directory for the latest TC39 PDF.
* http://www.ecma-international.org/publications/files/drafts/
*
* Previous ES5 Draft
* http://www.ecma-international.org/publications/files/drafts/tc39-2009-025.pdf
* This is a broken link to the previous draft of ES5 on which most of the
* numbered specification references and quotes herein were taken. Updating
* these references and quotes to reflect the new document would be a welcome
* volunteer project.
*
* @module
*/
/*whatsupdoc*/
//
// Function
// ========
//
// ES-5 15.3.4.5
// http://www.ecma-international.org/publications/files/drafts/tc39-2009-025.pdf
if (!Function.prototype.bind) {
var slice = Array.prototype.slice;
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.
// XXX this gets pretty close, for all intents and purposes, letting
// some duck-types slide
if (typeof target.apply !== "function" || typeof target.call !== "function")
return new TypeError();
// 3. Let A be a new (possibly empty) internal list of all of the
// argument values provided after thisArg (arg1, arg2 etc), in order.
var args = slice.call(arguments);
// 4. Let F be a new native ECMAScript object.
// 9. Set the [[Prototype]] internal property of F to the standard
// built-in Function prototype object as specified in 15.3.3.1.
// 10. Set the [[Call]] internal property of F as described in
// 15.3.4.5.1.
// 11. Set the [[Construct]] internal property of F as described in
// 15.3.4.5.2.
// 12. Set the [[HasInstance]] internal property of F as described in
// 15.3.4.5.3.
// 13. The [[Scope]] internal property of F is unused and need not
// exist.
var bound = function bound() {
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.
var self = Object.create(target.prototype);
target.apply(self, args.concat(slice.call(arguments)));
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.call.apply(
target,
args.concat(slice.call(arguments))
);
}
};
bound.length = (
// 14. If the [[Class]] internal property of Target is "Function", then
typeof target === "function" ?
// 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.
Math.max(target.length - args.length, 0) :
// 15. Else set the length own property of F to 0.
0
)
// 16. The length own property of F is given attributes as specified in
// 15.3.5.1.
// TODO
// 17. Set the [[Extensible]] internal property of F to true.
// TODO
// 18. Call the [[DefineOwnProperty]] internal method of F with
// arguments "caller", PropertyDescriptor {[[Value]]: null,
// [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]:
// false}, and false.
// TODO
// 19. Call the [[DefineOwnProperty]] internal method of F with
// arguments "arguments", PropertyDescriptor {[[Value]]: null,
// [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]:
// false}, and false.
// TODO
// NOTE Function objects created using Function.prototype.bind do not
// have a prototype property.
// XXX can't delete it in pure-js.
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 owns = call.bind(prototypeOfObject.hasOwnProperty);
var defineGetter, defineSetter, lookupGetter, lookupSetter, supportsAccessors;
// If JS engine supports accessors creating shortcuts.
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
if (!Array.isArray) {
Array.isArray = function isArray(obj) {
return Object.prototype.toString.call(obj) === "[object Array]";
};
}
// ES5 15.4.4.18
if (!Array.prototype.forEach) {
Array.prototype.forEach = function forEach(block, thisObject) {
var len = +this.length;
for (var i = 0; i < len; i++) {
if (i in this) {
block.call(thisObject, this[i], i, this);
}
}
};
}
// ES5 15.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 len = +this.length;
if (typeof fun !== "function")
throw new TypeError();
var res = new Array(len);
var thisp = arguments[1];
for (var i = 0; i < len; i++) {
if (i in this)
res[i] = fun.call(thisp, this[i], i, this);
}
return res;
};
}
// ES5 15.4.4.20
if (!Array.prototype.filter) {
Array.prototype.filter = function filter(block /*, thisp */) {
var values = [];
var thisp = arguments[1];
for (var i = 0; i < this.length; i++)
if (block.call(thisp, this[i]))
values.push(this[i]);
return values;
};
}
// ES5 15.4.4.16
if (!Array.prototype.every) {
Array.prototype.every = function every(block /*, thisp */) {
var thisp = arguments[1];
for (var i = 0; i < this.length; i++)
if (!block.call(thisp, this[i]))
return false;
return true;
};
}
// ES5 15.4.4.17
if (!Array.prototype.some) {
Array.prototype.some = function some(block /*, thisp */) {
var thisp = arguments[1];
for (var i = 0; i < this.length; i++)
if (block.call(thisp, this[i]))
return true;
return false;
};
}
// ES5 15.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 len = +this.length;
if (typeof fun !== "function")
throw new TypeError();
// no value to return if no initial value and an empty array
if (len === 0 && arguments.length === 1)
throw new TypeError();
var i = 0;
if (arguments.length >= 2) {
var rv = arguments[1];
} else {
do {
if (i in this) {
rv = this[i++];
break;
}
// if array contains no values, no initial value to return
if (++i >= len)
throw new TypeError();
} while (true);
}
for (; i < len; i++) {
if (i in this)
rv = fun.call(null, rv, this[i], i, this);
}
return rv;
};
}
// ES5 15.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 len = +this.length;
if (typeof fun !== "function")
throw new TypeError();
// no value to return if no initial value, empty array
if (len === 0 && arguments.length === 1)
throw new TypeError();
var i = len - 1;
if (arguments.length >= 2) {
var rv = arguments[1];
} else {
do {
if (i in this) {
rv = this[i--];
break;
}
// if array contains no values, no initial value to return
if (--i < 0)
throw new TypeError();
} while (true);
}
for (; i >= 0; i--) {
if (i in this)
rv = fun.call(null, rv, this[i], i, this);
}
return rv;
};
}
// ES5 15.4.4.14
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function indexOf(value /*, fromIndex */ ) {
var length = this.length;
if (!length)
return -1;
var i = arguments[1] || 0;
if (i >= length)
return -1;
if (i < 0)
i += length;
for (; i < length; i++) {
if (!owns(this, i))
continue;
if (value === this[i])
return i;
}
return -1;
};
}
// ES5 15.4.4.15
if (!Array.prototype.lastIndexOf) {
Array.prototype.lastIndexOf = function lastIndexOf(value /*, fromIndex */) {
var length = this.length;
if (!length)
return -1;
var i = arguments[1] || length;
if (i < 0)
i += length;
i = Math.min(i, length - 1);
for (; i >= 0; i--) {
if (!owns(this, i))
continue;
if (value === this[i])
return i;
}
return -1;
};
}
//
// Object
// ======
//
// ES5 15.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.prototype;
// or undefined if not available in this engine
};
}
// ES5 15.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 undefined;
var despriptor, getter, setter;
// If object has a property then it's for sure both `enumerable` and
// `configurable`.
despriptor = { 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
if (!Object.getOwnPropertyNames) {
Object.getOwnPropertyNames = function getOwnPropertyNames(object) {
return Object.keys(object);
};
}
// ES5 15.2.3.5
if (!Object.create) {
Object.create = function create(prototype, properties) {
var object;
if (prototype === null) {
object = { "__proto__": null };
} 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 (typeof properties !== "undefined")
Object.defineProperties(object, properties);
return object;
};
}
// ES5 15.2.3.6
if (!Object.defineProperty) {
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")
throw new TypeError(ERR_NON_OBJECT_TARGET + object);
if (typeof object !== "object" || object === null)
throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor);
// 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.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
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
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
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
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
if (!Object.isSealed) {
Object.isSealed = function isSealed(object) {
return false;
};
}
// ES5 15.2.3.12
if (!Object.isFrozen) {
Object.isFrozen = function isFrozen(object) {
return false;
};
}
// ES5 15.2.3.13
if (!Object.isExtensible) {
Object.isExtensible = function isExtensible(object) {
return true;
};
}
// ES5 15.2.3.14
// http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
if (!Object.keys) {
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
// Format a Date object as a string according to a subset of the ISO-8601 standard.
// Useful in Atom, among other things.
if (!Date.prototype.toISOString) {
Date.prototype.toISOString = function toISOString() {
return (
this.getUTCFullYear() + "-" +
(this.getUTCMonth() + 1) + "-" +
this.getUTCDate() + "T" +
this.getUTCHours() + ":" +
this.getUTCMinutes() + ":" +
this.getUTCSeconds() + "Z"
);
}
}
// ES5 15.9.4.4
if (!Date.now) {
Date.now = function now() {
return new Date().getTime();
};
}
// ES5 15.9.5.44
if (!Date.prototype.toJSON) {
Date.prototype.toJSON = function toJSON(key) {
// This function provides a String representation of a Date object for
// use by JSON.stringify (15.12.3). 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();
// 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.
};
}
// 15.9.4.2 Date.parse (string)
// 15.9.1.15 Date Time String Format
// Date.parse
// based on work shared by Daniel Friesen (dantman)
// http://gist.github.com/303249
if (isNaN(Date.parse("T00:00"))) {
// 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(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("^" +
"(?:" + // optional year-month-day
"(" + // year capture
"(?:[+-]\\d\\d)?" + // 15.9.1.15.1 Extended years
"\\d\\d\\d\\d" + // four-digit year
")" +
"(?:-" + // optional month-day
"(\\d\\d)" + // month capture
"(?:-" + // optional day
"(\\d\\d)" + // day capture
")?" +
")?" +
")?" +
"(?:T" + // hour:minute:second.subsecond
"(\\d\\d)" + // hour capture
":(\\d\\d)" + // minute capture
"(?::" + // optional :second.subsecond
"(\\d\\d)" + // second capture
"(?:\\.(\\d\\d\\d))?" + // milisecond capture
")?" +
")?" +
"(?:" + // time zone
"Z|" + // UTC capture
"([+-])(\\d\\d):(\\d\\d)" + // timezone offset
// capture sign, hour, minute
")?" +
"$");
// 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 the ISO dates we use
// TODO review specification to ascertain whether it is
// necessary to implement partial ISO date strings.
Date.parse = function parse(string) {
var match = isoDateExpression.exec(string);
if (match) {
match.shift(); // kill match[0], the full match
// recognize times without dates before normalizing the
// numeric values, for later use
var timeOnly = match[0] === undefined;
// parse numerics
for (var i = 0; i < 10; i++) {
// skip + or - for the timezone offset
if (i === 7)
continue;
// Note: parseInt would read 0-prefix numbers as
// octal. Number constructor or unary + work better
// here:
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]--;
}
// if no year-month-date is provided, return a milisecond
// quantity instead of a UTC date number value.
if (timeOnly)
return ((match[3] * 60 + match[4]) * 60 + match[5]) * 1000 + match[6];
// account for an explicit time zone offset if provided
var offset = (match[8] * 60 + match[9]) * 60 * 1000;
if (match[6] === "-")
offset = -offset;
return NativeDate.UTC.apply(this, match.slice(0, 7)) + offset;
}
return NativeDate.parse.apply(this, arguments);
};
return Date;
})(Date);
}
//
// String
// ======
//
// ES5 15.5.4.20
if (!String.prototype.trim) {
// http://blog.stevenlevithan.com/archives/faster-trim-javascript
var trimBeginRegexp = /^\s\s*/;
var trimEndRegexp = /\s\s*$/;
String.prototype.trim = function trim() {
return String(this).replace(trimBeginRegexp, '').replace(trimEndRegexp, '');
};
}
});

View file

@ -32,13 +32,10 @@ For more information about SproutCore, visit http://www.sproutcore.com
// Most of the following code is taken from SproutCore with a few changes. // Most of the following code is taken from SproutCore with a few changes.
define(function(require, exports, module) { define(function(require, exports, module) {
"use strict";
require("./fixoldbrowsers"); var oop = require("ace/lib/oop");
var oop = require("./oop"); /**
/*
* Helper functions and hashes for key handling. * Helper functions and hashes for key handling.
*/ */
var Keys = (function() { var Keys = (function() {
@ -48,8 +45,8 @@ var Keys = (function() {
}, },
KEY_MODS: { KEY_MODS: {
"ctrl": 1, "alt": 2, "option" : 2, "shift": 4, "ctrl": 1, "alt": 2, "option" : 2,
"super": 8, "meta": 8, "command": 8, "cmd": 8 "shift": 4, "meta": 8, "command": 8
}, },
FUNCTION_KEYS : { FUNCTION_KEYS : {
@ -70,17 +67,6 @@ var Keys = (function() {
44 : "Print", 44 : "Print",
45 : "Insert", 45 : "Insert",
46 : "Delete", 46 : "Delete",
96 : "Numpad0",
97 : "Numpad1",
98 : "Numpad2",
99 : "Numpad3",
100: "Numpad4",
101: "Numpad5",
102: "Numpad6",
103: "Numpad7",
104: "Numpad8",
105: "Numpad9",
'-13': "NumpadEnter",
112: "F1", 112: "F1",
113: "F2", 113: "F2",
114: "F3", 114: "F3",
@ -104,21 +90,14 @@ var Keys = (function() {
73: 'i', 74: 'j', 75: 'k', 76: 'l', 77: 'm', 78: 'n', 79: 'o', 73: 'i', 74: 'j', 75: 'k', 76: 'l', 77: 'm', 78: 'n', 79: 'o',
80: 'p', 81: 'q', 82: 'r', 83: 's', 84: 't', 85: 'u', 86: 'v', 80: 'p', 81: 'q', 82: 'r', 83: 's', 84: 't', 85: 'u', 86: 'v',
87: 'w', 88: 'x', 89: 'y', 90: 'z', 107: '+', 109: '-', 110: '.', 87: 'w', 88: 'x', 89: 'y', 90: 'z', 107: '+', 109: '-', 110: '.',
186: ';', 187: '=', 188: ',', 189: '-', 190: '.', 191: '/', 192: '`', 188: ',', 190: '.', 191: '/', 192: '`', 219: '[', 220: '\\',
219: '[', 220: '\\',221: ']', 222: '\'' 221: ']', 222: '\"'
} }
}; };
// A reverse map of FUNCTION_KEYS // A reverse map of FUNCTION_KEYS
var name, i;
for (i in ret.FUNCTION_KEYS) { for (i in ret.FUNCTION_KEYS) {
name = ret.FUNCTION_KEYS[i].toLowerCase(); var name = ret.FUNCTION_KEYS[i].toUpperCase();
ret[name] = parseInt(i, 10);
}
// A reverse map of PRINTABLE_KEYS
for (i in ret.PRINTABLE_KEYS) {
name = ret.PRINTABLE_KEYS[i].toLowerCase();
ret[name] = parseInt(i, 10); ret[name] = parseInt(i, 10);
} }
@ -128,36 +107,12 @@ var Keys = (function() {
oop.mixin(ret, ret.PRINTABLE_KEYS); oop.mixin(ret, ret.PRINTABLE_KEYS);
oop.mixin(ret, ret.FUNCTION_KEYS); oop.mixin(ret, ret.FUNCTION_KEYS);
// aliases
ret.enter = ret["return"];
ret.escape = ret.esc;
ret.del = ret["delete"];
// workaround for firefox bug
ret[173] = '-';
(function() {
var mods = ["cmd", "ctrl", "alt", "shift"];
for (var i = Math.pow(2, mods.length); i--;) {
ret.KEY_MODS[i] = mods.filter(function(x) {
return i & ret.KEY_MODS[x];
}).join("-") + "-";
}
})();
ret.KEY_MODS[0] = "";
ret.KEY_MODS[-1] = "input-";
return ret; return ret;
})(); })();
oop.mixin(exports, Keys); oop.mixin(exports, Keys);
exports.keyCodeToString = function(keyCode) { exports.keyCodeToString = function(keyCode) {
// Language-switching keystroke in Chrome/Linux emits keyCode 0. return (Keys[keyCode] || String.fromCharCode(keyCode)).toLowerCase();
var keyString = Keys[keyCode]; }
if (typeof keyString != "string")
keyString = String.fromCharCode(keyCode);
return keyString.toLowerCase();
};
}); });

150
ace/lib/lang.js Normal file
View file

@ -0,0 +1,150 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
exports.stringReverse = function(string) {
return string.split("").reverse().join("");
};
exports.stringRepeat = function (string, count) {
return new Array(count + 1).join(string);
};
var trimBeginRegexp = /^\s\s*/;
var trimEndRegexp = /\s\s*$/;
exports.stringTrimLeft = function (string) {
return string.replace(trimBeginRegexp, '')
};
exports.stringTrimRight = function (string) {
return string.replace(trimEndRegexp, '');
};
exports.copyObject = function(obj) {
var copy = {};
for (var key in obj) {
copy[key] = obj[key];
}
return copy;
};
exports.copyArray = function(array){
var copy = [];
for (i=0, l=array.length; i<l; i++) {
if (array[i] && typeof array[i] == "object")
copy[i] = this.copyObject( array[i] );
else
copy[i] = array[i]
}
return copy;
};
exports.deepCopy = function (obj) {
if (typeof obj != "object") {
return obj;
}
var copy = obj.constructor();
for (var key in obj) {
if (typeof obj[key] == "object") {
copy[key] = this.deepCopy(obj[key]);
} else {
copy[key] = obj[key];
}
}
return copy;
}
exports.arrayToMap = function(arr) {
var map = {};
for (var i=0; i<arr.length; i++) {
map[arr[i]] = 1;
}
return map;
};
/**
* splice out of 'array' anything that === 'value'
*/
exports.arrayRemove = function(array, value) {
for (var i = 0; i <= array.length; i++) {
if (value === array[i]) {
array.splice(i, 1);
}
}
};
exports.escapeRegExp = function(str) {
return str.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1');
};
exports.deferredCall = function(fcn) {
var timer = null;
var callback = function() {
timer = null;
fcn();
};
var deferred = function(timeout) {
if (!timer) {
timer = setTimeout(callback, timeout || 0);
}
return deferred;
}
deferred.schedule = deferred;
deferred.call = function() {
this.cancel();
fcn();
return deferred;
};
deferred.cancel = function() {
clearTimeout(timer);
timer = null;
return deferred;
};
return deferred;
};
});

60
ace/lib/oop.js Normal file
View file

@ -0,0 +1,60 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
exports.inherits = (function() {
var tempCtor = function() {};
return function(ctor, superCtor) {
tempCtor.prototype = superCtor.prototype;
ctor.super_ = superCtor.prototype;
ctor.prototype = new tempCtor();
ctor.prototype.constructor = ctor;
}
}());
exports.mixin = function(obj, mixin) {
for (var key in mixin) {
obj[key] = mixin[key];
}
};
exports.implement = function(proto, mixin) {
exports.mixin(proto, mixin);
};
});

View file

@ -1,16 +1,13 @@
/*
* Based on code from:
*
* XRegExp 1.5.0
* (c) 2007-2010 Steven Levithan
* MIT License
* <http://xregexp.com>
* Provides an augmented, extensible, cross-browser implementation of regular expressions,
* including support for additional syntax, flags, and methods
*/
define(function(require, exports, module) { define(function(require, exports, module) {
"use strict";
// Based on code from:
//
// XRegExp 1.5.0
// (c) 2007-2010 Steven Levithan
// MIT License
// <http://xregexp.com>
// Provides an augmented, extensible, cross-browser implementation of regular expressions,
// including support for additional syntax, flags, and methods
//--------------------------------- //---------------------------------
// Private variables // Private variables
@ -30,9 +27,6 @@ define(function(require, exports, module) {
return !x.lastIndex; return !x.lastIndex;
}(); }();
if (compliantLastIndexIncrement && compliantExecNpcg)
return;
//--------------------------------- //---------------------------------
// Overriden native methods // Overriden native methods
//--------------------------------- //---------------------------------
@ -45,7 +39,7 @@ define(function(require, exports, module) {
RegExp.prototype.exec = function (str) { RegExp.prototype.exec = function (str) {
var match = real.exec.apply(this, arguments), var match = real.exec.apply(this, arguments),
name, r2; name, r2;
if ( typeof(str) == 'string' && match) { if (match) {
// Fix browsers whose `exec` methods don't consistently return `undefined` for // Fix browsers whose `exec` methods don't consistently return `undefined` for
// nonparticipating capturing groups // nonparticipating capturing groups
if (!compliantExecNpcg && match.length > 1 && indexOf(match, "") > -1) { if (!compliantExecNpcg && match.length > 1 && indexOf(match, "") > -1) {
@ -98,7 +92,7 @@ define(function(require, exports, module) {
(regex.multiline ? "m" : "") + (regex.multiline ? "m" : "") +
(regex.extended ? "x" : "") + // Proposed for ES4; included in AS3 (regex.extended ? "x" : "") + // Proposed for ES4; included in AS3
(regex.sticky ? "y" : ""); (regex.sticky ? "y" : "");
} };
function indexOf (array, item, from) { function indexOf (array, item, from) {
if (Array.prototype.indexOf) // Use the native array method if available if (Array.prototype.indexOf) // Use the native array method if available
@ -108,6 +102,6 @@ define(function(require, exports, module) {
return i; return i;
} }
return -1; return -1;
} };
}); });

99
ace/lib/useragent.js Normal file
View file

@ -0,0 +1,99 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var os = (navigator.platform.match(/mac|win|linux/i) || ["other"])[0].toLowerCase();
var ua = navigator.userAgent;
var av = navigator.appVersion;
/** 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 = ! + "\v1";
/** Is this Firefox or related? */
exports.isGecko = exports.isMozilla = window.controllers && window.navigator.product === "Gecko";
/** oldGecko == rev < 2.0 **/
exports.isOldGecko = exports.isGecko && /rv\:1/.test(navigator.userAgent);
/** 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;
/**
* 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'];
}
};
});

97
ace/mode/behaviour.js Normal file
View file

@ -0,0 +1,97 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Chris Spencer <chris.ag.spencer AT googlemail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
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;
});

View file

@ -0,0 +1,228 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Chris Spencer <chris.ag.spencer AT googlemail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var Behaviour = require('ace/mode/behaviour').Behaviour;
var CstyleBehaviour = function () {
this.add("braces", "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 {
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) {
return {
text: '',
selection: [1, 1]
}
}
}
} else if (text == "\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 false;
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]
}
}
}
return false;
});
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;
}
}
return false;
});
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 {
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) {
return {
text: '',
selection: [1, 1]
}
}
}
}
return false;
});
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;
}
}
return false;
});
this.add("string_dquotes", "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 {
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 false;
}
// Find what token we're inside.
var tokens = session.getTokens(selection.start.row, selection.start.row)[0].tokens;
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('"');
}
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('"') === token.value.length-1)))) {
return {
text: '""',
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 == '"') {
return {
text: '',
selection: [1, 1]
}
}
}
}
}
return false;
});
this.add("string_dquotes", "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;
}
}
return false;
});
}
oop.inherits(CstyleBehaviour, Behaviour);
exports.CstyleBehaviour = CstyleBehaviour;
});

92
ace/mode/behaviour/xml.js Normal file
View file

@ -0,0 +1,92 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Chris Spencer <chris.ag.spencer AT googlemail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var Behaviour = require('ace/mode/behaviour').Behaviour;
var CstyleBehaviour = require('ace/mode/behaviour/cstyle').CstyleBehaviour;
var XmlBehaviour = function () {
this.inherit(CstyleBehaviour, ["string_dquotes"]); // Get string behaviour
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 false;
} else {
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 == '>') { // need some kind of matching check here
return {
text: '',
selection: [1, 1]
}
}
} else 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 == '</') {
var indent = this.$getIndent(session.doc.getLine(cursor.row)) + session.getTabString();
var next_indent = this.$getIndent(session.doc.getLine(cursor.row));
return {
text: '\n' + indent + '\n' + next_indent,
selection: [1, indent.length, 1, indent.length]
}
}
}
return false;
});
}
oop.inherits(XmlBehaviour, Behaviour);
exports.XmlBehaviour = XmlBehaviour;
});

130
ace/mode/c_cpp.js Normal file
View file

@ -0,0 +1,130 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Gastón Kleiman <gaston.kleiman AT gmail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var TextMode = require("ace/mode/text").Mode;
var Tokenizer = require("ace/tokenizer").Tokenizer;
var c_cppHighlightRules = require("ace/mode/c_cpp_highlight_rules").c_cppHighlightRules;
var MatchingBraceOutdent = require("ace/mode/matching_brace_outdent").MatchingBraceOutdent;
var Range = require("ace/range").Range;
var CstyleBehaviour = require("ace/mode/behaviour/cstyle").CstyleBehaviour;
var Mode = function() {
this.$tokenizer = new Tokenizer(new c_cppHighlightRules().getRules());
this.$outdent = new MatchingBraceOutdent();
this.$behaviour = new CstyleBehaviour();
};
oop.inherits(Mode, TextMode);
(function() {
this.toggleCommentLines = function(state, doc, startRow, endRow) {
var outdent = true;
var outentedRows = [];
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;
});

View file

@ -0,0 +1,176 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Gastón Kleiman <gaston.kleiman AT gmail DOT com>
*
* Based on Bespin's C/C++ Syntax Plugin by Marc McIntyre.
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var lang = require("ace/lib/lang");
var DocCommentHighlightRules = require("ace/mode/doc_comment_highlight_rules").DocCommentHighlightRules;
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
var c_cppHighlightRules = function() {
var keywords = lang.arrayToMap(
("and|double|not_eq|throw|and_eq|dynamic_cast|operator|true|" +
"asm|else|or|try|auto|enum|or_eq|typedef|bitand|explicit|private|" +
"typeid|bitor|extern|protected|typename|bool|false|public|union|" +
"break|float|register|unsigned|case|fro|reinterpret-cast|using|catch|" +
"friend|return|virtual|char|goto|short|void|class|if|signed|volatile|" +
"compl|inline|sizeof|wchar_t|const|int|static|while|const-cast|long|" +
"static_cast|xor|continue|mutable|struct|xor_eq|default|namespace|" +
"switch|delete|new|template|do|not|this|for").split("|")
);
var buildinConstants = lang.arrayToMap(
("NULL").split("|")
);
// regexp must not have capturing parentheses. Use (?:) instead.
// regexps are ordered -> the first match is used
this.$rules = {
"start" : [
{
token : "comment",
regex : "\\/\\/.*$"
},
new 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", // <CONSTANT>
regex : "<[a-zA-Z0-9.]+>"
}, {
token : "keyword", // pre-compiler directivs
regex : "(?:#include|#pragma|#line|#define|#undef|#ifdef|#else|#elif|#endif|#ifndef)"
}, {
token : function(value) {
if (value == "this")
return "variable.language";
else if (keywords.hasOwnProperty(value))
return "keyword";
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
else
return "identifier";
},
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, {
token : "keyword.operator",
regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|==|=|!=|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|new|delete|typeof|void)"
}, {
token : "lparen",
regex : "[[({]"
}, {
token : "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-",
[ new DocCommentHighlightRules().getEndRule("start") ]);
};
oop.inherits(c_cppHighlightRules, TextHighlightRules);
exports.c_cppHighlightRules = c_cppHighlightRules;
});

123
ace/mode/clojure.js Normal file
View file

@ -0,0 +1,123 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Shlomo Zalman Heigh <shlomozalmanheigh AT gmail DOT com>
* Carin Meier
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var TextMode = require("ace/mode/text").Mode;
var Tokenizer = require("ace/tokenizer").Tokenizer;
var ClojureHighlightRules = require("ace/mode/clojure_highlight_rules").ClojureHighlightRules;
var MatchingParensOutdent = require("ace/mode/matching_parens_outdent").MatchingParensOutdent;
var Range = require("ace/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 outentedRows = [];
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 startingIndent = indent;
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(/[\(\[]/);
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;
});

View file

@ -0,0 +1,219 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Shlomo Zalman Heigh <shlomozalmanheigh AT gmail DOT com>
* Carin Meier
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var lang = require("ace/lib/lang");
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
var ClojureHighlightRules = function() {
var builtinFunctions = lang.arrayToMap(
('* *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* + - -> -&gt; ->> -&gt;&gt; .. / < &lt; <= &lt;= = ' +
'== > &gt; >= &gt;= 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 ').split(" ")
);
var keywords = lang.arrayToMap(
('def do fn if let loop monitor-enter monitor-exit new quote recur set! ' +
'throw try var').split(" ")
);
var buildinConstants = lang.arrayToMap(
("true false nil").split(" ")
);
// 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 : function(value) {
if (keywords.hasOwnProperty(value))
return "keyword";
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
else if (builtinFunctions.hasOwnProperty(value))
return "support.function";
else
return "identifier";
},
// TODO: Unicode escape sequences
// TODO: Unicode identifiers
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, {
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, {
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 : ".+"
}
]
};
};
oop.inherits(ClojureHighlightRules, TextHighlightRules);
exports.ClojureHighlightRules = ClojureHighlightRules;
});

125
ace/mode/coffee.js Normal file
View file

@ -0,0 +1,125 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Satoshi Murakami <murky.satyr AT gmail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var Tokenizer = require("ace/tokenizer").Tokenizer;
var Rules = require("ace/mode/coffee_highlight_rules").CoffeeHighlightRules;
var Outdent = require("ace/mode/matching_brace_outdent").MatchingBraceOutdent;
var Range = require("ace/range").Range;
var TextMode = require("ace/mode/text").Mode;
var WorkerClient = require("ace/worker/worker_client").WorkerClient;
var oop = require("ace/lib/oop");
function Mode() {
this.$tokenizer = new Tokenizer(new Rules().getRules());
this.$outdent = new Outdent();
}
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 doc = session.getDocument();
var worker = new WorkerClient(["ace"], "worker-coffee.js", "ace/mode/coffee_worker", "Worker");
worker.call("setValue", [doc.getValue()]);
doc.on("change", function(e) {
e.range = {
start: e.data.range.start,
end: e.data.range.end
};
worker.emit("change", e);
});
worker.on("error", function(e) {
session.setAnnotations([e.data]);
});
worker.on("ok", function(e) {
session.clearAnnotations();
});
};
}).call(Mode.prototype);
exports.Mode = Mode;
});

View file

@ -0,0 +1,63 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var Lexer = require("ace/mode/coffee/lexer").Lexer;
var parser = require("ace/mode/coffee/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('ace/mode/coffee/nodes');
exports.parse = function(code) {
return parser.parse(lexer.tokenize(code));
};
});

View file

@ -0,0 +1,92 @@
/**
* Copyright (c) 2011 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) {
var extend, flatten;
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];
};
});

View file

@ -1,6 +1,6 @@
/** /**
* Copyright (c) 2009-2013 Jeremy Ashkenas * Copyright (c) 2011 Jeremy Ashkenas
* *
* Permission is hereby granted, free of charge, to any person * Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation * obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without * files (the "Software"), to deal in the Software without
@ -21,84 +21,60 @@
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE. * OTHER DEALINGS IN THE SOFTWARE.
*
*/ */
define(function(require, exports, module) { define(function(require, exports, module) {
// Generated by CoffeeScript 1.6.3
var ASSIGNED, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HEREDOC, HEREDOC_ILLEGAL, HEREDOC_INDENT, HEREGEX, HEREGEX_OMIT, IDENTIFIER, INDEXABLE, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LINE_BREAK, LINE_CONTINUER, LOGIC, Lexer, MATH, MULTILINER, MULTI_DENT, NOT_REGEX, NOT_SPACED_REGEX, NO_NEWLINE, NUMBER, OPERATOR, REGEX, RELATION, RESERVED, Rewriter, SHIFT, SIMPLESTR, TRAILING_SPACES, UNARY, WHITESPACE, compact, count, key, last, starts, _ref;
var BOM, 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, invertLiterate, key, last, locationDataToString, repeat, starts, throwSyntaxError, _ref, _ref1, var __indexOf = Array.prototype.indexOf || function(item) {
__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; }; for (var i = 0, l = this.length; i < l; i++) {
if (this[i] === item) return i;
_ref = require('./rewriter'), Rewriter = _ref.Rewriter, INVERSES = _ref.INVERSES; }
return -1;
_ref1 = require('./helpers'), count = _ref1.count, starts = _ref1.starts, compact = _ref1.compact, last = _ref1.last, repeat = _ref1.repeat, invertLiterate = _ref1.invertLiterate, locationDataToString = _ref1.locationDataToString, throwSyntaxError = _ref1.throwSyntaxError; };
Rewriter = require('ace/mode/coffee/rewriter').Rewriter;
_ref = require('ace/mode/coffee/helpers'), count = _ref.count, starts = _ref.starts, compact = _ref.compact, last = _ref.last;
exports.Lexer = Lexer = (function() { exports.Lexer = Lexer = (function() {
function Lexer() {} function Lexer() {}
Lexer.prototype.tokenize = function(code, opts) { Lexer.prototype.tokenize = function(code, opts) {
var consumed, i, tag, _ref2; var i;
if (opts == null) { if (opts == null) {
opts = {}; opts = {};
} }
this.literate = opts.literate; 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.indent = 0;
this.baseIndent = 0;
this.indebt = 0; this.indebt = 0;
this.outdebt = 0; this.outdebt = 0;
this.indents = []; this.indents = [];
this.ends = [];
this.tokens = []; this.tokens = [];
this.chunkLine = opts.line || 0;
this.chunkColumn = opts.column || 0;
code = this.clean(code);
i = 0; i = 0;
while (this.chunk = code.slice(i)) { while (this.chunk = code.slice(i)) {
consumed = this.identifierToken() || this.commentToken() || this.whitespaceToken() || this.lineToken() || this.heredocToken() || this.stringToken() || this.numberToken() || this.regexToken() || this.jsToken() || this.literalToken(); i += this.identifierToken() || this.commentToken() || this.whitespaceToken() || this.lineToken() || this.heredocToken() || this.stringToken() || this.numberToken() || this.regexToken() || this.jsToken() || this.literalToken();
_ref2 = this.getLineAndColumnFromChunk(consumed), this.chunkLine = _ref2[0], this.chunkColumn = _ref2[1];
i += consumed;
} }
this.closeIndentation(); this.closeIndentation();
if (tag = this.ends.pop()) {
this.error("missing " + tag);
}
if (opts.rewrite === false) { if (opts.rewrite === false) {
return this.tokens; return this.tokens;
} }
return (new Rewriter).rewrite(this.tokens); return (new Rewriter).rewrite(this.tokens);
}; };
Lexer.prototype.clean = function(code) {
if (code.charCodeAt(0) === BOM) {
code = code.slice(1);
}
code = code.replace(/\r/g, '').replace(TRAILING_SPACES, '');
if (WHITESPACE.test(code)) {
code = "\n" + code;
this.chunkLine--;
}
if (this.literate) {
code = invertLiterate(code);
}
return code;
};
Lexer.prototype.identifierToken = function() { Lexer.prototype.identifierToken = function() {
var colon, colonOffset, forcedIdentifier, id, idLength, input, match, poppedToken, prev, tag, tagToken, _ref2, _ref3, _ref4; var colon, forcedIdentifier, id, input, match, prev, tag, _ref2, _ref3;
if (!(match = IDENTIFIER.exec(this.chunk))) { if (!(match = IDENTIFIER.exec(this.chunk))) {
return 0; return 0;
} }
input = match[0], id = match[1], colon = match[2]; input = match[0], id = match[1], colon = match[2];
idLength = id.length;
poppedToken = void 0;
if (id === 'own' && this.tag() === 'FOR') { if (id === 'own' && this.tag() === 'FOR') {
this.token('OWN', id); this.token('OWN', id);
return id.length; return id.length;
} }
forcedIdentifier = colon || (prev = last(this.tokens)) && (((_ref2 = prev[0]) === '.' || _ref2 === '?.' || _ref2 === '::' || _ref2 === '?::') || !prev.spaced && prev[0] === '@'); forcedIdentifier = colon || (prev = last(this.tokens)) && (((_ref2 = prev[0]) === '.' || _ref2 === '?.' || _ref2 === '::') || !prev.spaced && prev[0] === '@');
tag = 'IDENTIFIER'; tag = 'IDENTIFIER';
if (!forcedIdentifier && (__indexOf.call(JS_KEYWORDS, id) >= 0 || __indexOf.call(COFFEE_KEYWORDS, id) >= 0)) { if (__indexOf.call(JS_KEYWORDS, id) >= 0 || !forcedIdentifier && __indexOf.call(COFFEE_KEYWORDS, id) >= 0) {
tag = id.toUpperCase(); tag = id.toUpperCase();
if (tag === 'WHEN' && (_ref3 = this.tag(), __indexOf.call(LINE_BREAK, _ref3) >= 0)) { if (tag === 'WHEN' && (_ref3 = this.tag(), __indexOf.call(LINE_BREAK, _ref3) >= 0)) {
tag = 'LEADING_WHEN'; tag = 'LEADING_WHEN';
@ -115,7 +91,7 @@ define(function(require, exports, module) {
} else { } else {
tag = 'RELATION'; tag = 'RELATION';
if (this.value() === '!') { if (this.value() === '!') {
poppedToken = this.tokens.pop(); this.tokens.pop();
id = '!' + id; id = '!' + id;
} }
} }
@ -127,7 +103,7 @@ define(function(require, exports, module) {
id = new String(id); id = new String(id);
id.reserved = true; id.reserved = true;
} else if (__indexOf.call(RESERVED, id) >= 0) { } else if (__indexOf.call(RESERVED, id) >= 0) {
this.error("reserved word \"" + id + "\""); this.identifierError(id);
} }
} }
if (!forcedIdentifier) { if (!forcedIdentifier) {
@ -146,79 +122,58 @@ define(function(require, exports, module) {
return 'LOGIC'; return 'LOGIC';
case 'true': case 'true':
case 'false': case 'false':
case 'null':
case 'undefined':
return 'BOOL'; return 'BOOL';
case 'break': case 'break':
case 'continue': case 'continue':
case 'debugger':
return 'STATEMENT'; return 'STATEMENT';
default: default:
return tag; return tag;
} }
})(); })();
} }
tagToken = this.token(tag, id, 0, idLength); this.token(tag, id);
if (poppedToken) {
_ref4 = [poppedToken[2].first_line, poppedToken[2].first_column], tagToken[2].first_line = _ref4[0], tagToken[2].first_column = _ref4[1];
}
if (colon) { if (colon) {
colonOffset = input.lastIndexOf(':'); this.token(':', ':');
this.token(':', ':', colonOffset, colon.length);
} }
return input.length; return input.length;
}; };
Lexer.prototype.numberToken = function() { Lexer.prototype.numberToken = function() {
var binaryLiteral, lexedLength, match, number, octalLiteral; var match, number;
if (!(match = NUMBER.exec(this.chunk))) { if (!(match = NUMBER.exec(this.chunk))) {
return 0; return 0;
} }
number = match[0]; number = match[0];
if (/^0[BOX]/.test(number)) { this.token('NUMBER', number);
this.error("radix prefix '" + number + "' must be lowercase"); return number.length;
} 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, 0, lexedLength);
return lexedLength;
}; };
Lexer.prototype.stringToken = function() { Lexer.prototype.stringToken = function() {
var octalEsc, quote, string, trimmed; var match, string;
switch (quote = this.chunk.charAt(0)) { switch (this.chunk.charAt(0)) {
case "'": case "'":
string = SIMPLESTR.exec(this.chunk)[0]; if (!(match = SIMPLESTR.exec(this.chunk))) {
return 0;
}
this.token('STRING', (string = match[0]).replace(MULTILINER, '\\\n'));
break; break;
case '"': case '"':
string = this.balancedString(this.chunk, '"'); if (!(string = this.balancedString(this.chunk, '"'))) {
} return 0;
if (!string) { }
return 0; if (0 < string.indexOf('#{', 1)) {
} this.interpolateString(string.slice(1, -1));
trimmed = this.removeNewlines(string.slice(1, -1)); } else {
if (quote === '"' && 0 < string.indexOf('#{', 1)) { this.token('STRING', this.escapeLines(string));
this.interpolateString(trimmed, { }
strOffset: 1, break;
lexedLength: string.length default:
}); return 0;
} else {
this.token('STRING', quote + this.escapeLines(trimmed) + quote, 0, string.length);
}
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; return string.length;
}; };
Lexer.prototype.heredocToken = function() { Lexer.prototype.heredocToken = function() {
var doc, heredoc, match, quote; var doc, heredoc, match, quote;
if (!(match = HEREDOC.exec(this.chunk))) { if (!(match = HEREDOC.exec(this.chunk))) {
@ -232,16 +187,14 @@ define(function(require, exports, module) {
}); });
if (quote === '"' && 0 <= doc.indexOf('#{')) { if (quote === '"' && 0 <= doc.indexOf('#{')) {
this.interpolateString(doc, { this.interpolateString(doc, {
heredoc: true, heredoc: true
strOffset: 3,
lexedLength: heredoc.length
}); });
} else { } else {
this.token('STRING', this.makeString(doc, quote, true), 0, heredoc.length); this.token('STRING', this.makeString(doc, quote, true));
} }
this.line += count(heredoc, '\n');
return heredoc.length; return heredoc.length;
}; };
Lexer.prototype.commentToken = function() { Lexer.prototype.commentToken = function() {
var comment, here, match; var comment, here, match;
if (!(match = this.chunk.match(COMMENT))) { if (!(match = this.chunk.match(COMMENT))) {
@ -251,29 +204,29 @@ define(function(require, exports, module) {
if (here) { if (here) {
this.token('HERECOMMENT', this.sanitizeHeredoc(here, { this.token('HERECOMMENT', this.sanitizeHeredoc(here, {
herecomment: true, herecomment: true,
indent: repeat(' ', this.indent) indent: Array(this.indent + 1).join(' ')
}), 0, comment.length); }));
this.token('TERMINATOR', '\n');
} }
this.line += count(comment, '\n');
return comment.length; return comment.length;
}; };
Lexer.prototype.jsToken = function() { Lexer.prototype.jsToken = function() {
var match, script; var match, script;
if (!(this.chunk.charAt(0) === '`' && (match = JSTOKEN.exec(this.chunk)))) { if (!(this.chunk.charAt(0) === '`' && (match = JSTOKEN.exec(this.chunk)))) {
return 0; return 0;
} }
this.token('JS', (script = match[0]).slice(1, -1), 0, script.length); this.token('JS', (script = match[0]).slice(1, -1));
return script.length; return script.length;
}; };
Lexer.prototype.regexToken = function() { Lexer.prototype.regexToken = function() {
var flags, length, match, prev, regex, _ref2, _ref3; var match, prev, regex, _ref2;
if (this.chunk.charAt(0) !== '/') { if (this.chunk.charAt(0) !== '/') {
return 0; return 0;
} }
if (match = HEREGEX.exec(this.chunk)) { if (match = HEREGEX.exec(this.chunk)) {
length = this.heregexToken(match); this.line += count(match[0], '\n');
return length; return this.heregexToken(match);
} }
prev = last(this.tokens); prev = last(this.tokens);
if (prev && (_ref2 = prev[0], __indexOf.call((prev.spaced ? NOT_REGEX : NOT_SPACED_REGEX), _ref2) >= 0)) { if (prev && (_ref2 = prev[0], __indexOf.call((prev.spaced ? NOT_REGEX : NOT_SPACED_REGEX), _ref2) >= 0)) {
@ -282,84 +235,63 @@ define(function(require, exports, module) {
if (!(match = REGEX.exec(this.chunk))) { if (!(match = REGEX.exec(this.chunk))) {
return 0; return 0;
} }
_ref3 = match, match = _ref3[0], regex = _ref3[1], flags = _ref3[2]; regex = match[0];
if (regex.slice(0, 2) === '/*') { this.token('REGEX', regex === '//' ? '/(?:)/' : regex);
this.error('regular expressions cannot begin with `*`'); return regex.length;
}
if (regex === '//') {
regex = '/(?:)/';
}
this.token('REGEX', "" + regex + flags, 0, match.length);
return match.length;
}; };
Lexer.prototype.heregexToken = function(match) { Lexer.prototype.heregexToken = function(match) {
var body, flags, flagsOffset, heregex, plusToken, prev, re, tag, token, tokens, value, _i, _len, _ref2, _ref3, _ref4; var body, flags, heregex, re, tag, tokens, value, _i, _len, _ref2, _ref3, _ref4, _ref5;
heregex = match[0], body = match[1], flags = match[2]; heregex = match[0], body = match[1], flags = match[2];
if (0 > body.indexOf('#{')) { if (0 > body.indexOf('#{')) {
re = this.escapeLines(body.replace(HEREGEX_OMIT, '$1$2').replace(/\//g, '\\/'), true); re = body.replace(HEREGEX_OMIT, '').replace(/\//g, '\\/');
if (re.match(/^\*/)) { this.token('REGEX', "/" + (re || '(?:)') + "/" + flags);
this.error('regular expressions cannot begin with `*`');
}
this.token('REGEX', "/" + (re || '(?:)') + "/" + flags, 0, heregex.length);
return heregex.length; return heregex.length;
} }
this.token('IDENTIFIER', 'RegExp', 0, 0); this.token('IDENTIFIER', 'RegExp');
this.token('CALL_START', '(', 0, 0); this.tokens.push(['CALL_START', '(']);
tokens = []; tokens = [];
_ref2 = this.interpolateString(body, { _ref2 = this.interpolateString(body, {
regex: true regex: true
}); });
for (_i = 0, _len = _ref2.length; _i < _len; _i++) { for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
token = _ref2[_i]; _ref3 = _ref2[_i], tag = _ref3[0], value = _ref3[1];
tag = token[0], value = token[1];
if (tag === 'TOKENS') { if (tag === 'TOKENS') {
tokens.push.apply(tokens, value); tokens.push.apply(tokens, value);
} else if (tag === 'NEOSTRING') { } else {
if (!(value = value.replace(HEREGEX_OMIT, '$1$2'))) { if (!(value = value.replace(HEREGEX_OMIT, ''))) {
continue; continue;
} }
value = value.replace(/\\/g, '\\\\'); value = value.replace(/\\/g, '\\\\');
token[0] = 'STRING'; tokens.push(['STRING', this.makeString(value, '"', true)]);
token[1] = this.makeString(value, '"', true);
tokens.push(token);
} else {
this.error("Unexpected " + tag);
} }
prev = last(this.tokens); tokens.push(['+', '+']);
plusToken = ['+', '+'];
plusToken[2] = prev[2];
tokens.push(plusToken);
} }
tokens.pop(); tokens.pop();
if (((_ref3 = tokens[0]) != null ? _ref3[0] : void 0) !== 'STRING') { if (((_ref4 = tokens[0]) != null ? _ref4[0] : void 0) !== 'STRING') {
this.token('STRING', '""', 0, 0); this.tokens.push(['STRING', '""'], ['+', '+']);
this.token('+', '+', 0, 0);
} }
(_ref4 = this.tokens).push.apply(_ref4, tokens); (_ref5 = this.tokens).push.apply(_ref5, tokens);
if (flags) { if (flags) {
flagsOffset = heregex.lastIndexOf(flags); this.tokens.push([',', ','], ['STRING', '"' + flags + '"']);
this.token(',', ',', flagsOffset, 0);
this.token('STRING', '"' + flags + '"', flagsOffset, flags.length);
} }
this.token(')', ')', heregex.length - 1, 0); this.token(')', ')');
return heregex.length; return heregex.length;
}; };
Lexer.prototype.lineToken = function() { Lexer.prototype.lineToken = function() {
var diff, indent, match, noNewlines, size; var diff, indent, match, noNewlines, prev, size;
if (!(match = MULTI_DENT.exec(this.chunk))) { if (!(match = MULTI_DENT.exec(this.chunk))) {
return 0; return 0;
} }
indent = match[0]; indent = match[0];
this.seenFor = false; this.line += count(indent, '\n');
prev = last(this.tokens, 1);
size = indent.length - 1 - indent.lastIndexOf('\n'); size = indent.length - 1 - indent.lastIndexOf('\n');
noNewlines = this.unfinished(); noNewlines = this.unfinished();
if (size - this.indebt === this.indent) { if (size - this.indebt === this.indent) {
if (noNewlines) { if (noNewlines) {
this.suppressNewlines(); this.suppressNewlines();
} else { } else {
this.newlineToken(0); this.newlineToken();
} }
return indent.length; return indent.length;
} }
@ -369,26 +301,18 @@ define(function(require, exports, module) {
this.suppressNewlines(); this.suppressNewlines();
return indent.length; return indent.length;
} }
if (!this.tokens.length) {
this.baseIndent = this.indent = size;
return indent.length;
}
diff = size - this.indent + this.outdebt; diff = size - this.indent + this.outdebt;
this.token('INDENT', diff, indent.length - size, size); this.token('INDENT', diff);
this.indents.push(diff); this.indents.push(diff);
this.ends.push('OUTDENT');
this.outdebt = this.indebt = 0; this.outdebt = this.indebt = 0;
} else if (size < this.baseIndent) {
this.error('missing indentation', indent.length);
} else { } else {
this.indebt = 0; this.indebt = 0;
this.outdentToken(this.indent - size, noNewlines, indent.length); this.outdentToken(this.indent - size, noNewlines);
} }
this.indent = size; this.indent = size;
return indent.length; return indent.length;
}; };
Lexer.prototype.outdentToken = function(moveOut, noNewlines, close) {
Lexer.prototype.outdentToken = function(moveOut, noNewlines, outdentLength) {
var dent, len; var dent, len;
while (moveOut > 0) { while (moveOut > 0) {
len = this.indents.length - 1; len = this.indents.length - 1;
@ -401,25 +325,20 @@ define(function(require, exports, module) {
this.outdebt -= this.indents[len]; this.outdebt -= this.indents[len];
moveOut -= this.indents[len]; moveOut -= this.indents[len];
} else { } else {
dent = this.indents.pop() + this.outdebt; dent = this.indents.pop() - this.outdebt;
moveOut -= dent; moveOut -= dent;
this.outdebt = 0; this.outdebt = 0;
this.pair('OUTDENT'); this.token('OUTDENT', dent);
this.token('OUTDENT', dent, 0, outdentLength);
} }
} }
if (dent) { if (dent) {
this.outdebt -= moveOut; this.outdebt -= moveOut;
} }
while (this.value() === ';') {
this.tokens.pop();
}
if (!(this.tag() === 'TERMINATOR' || noNewlines)) { if (!(this.tag() === 'TERMINATOR' || noNewlines)) {
this.token('TERMINATOR', '\n', outdentLength, 0); this.token('TERMINATOR', '\n');
} }
return this; return this;
}; };
Lexer.prototype.whitespaceToken = function() { Lexer.prototype.whitespaceToken = function() {
var match, nline, prev; var match, nline, prev;
if (!((match = WHITESPACE.exec(this.chunk)) || (nline = this.chunk.charAt(0) === '\n'))) { if (!((match = WHITESPACE.exec(this.chunk)) || (nline = this.chunk.charAt(0) === '\n'))) {
@ -435,24 +354,18 @@ define(function(require, exports, module) {
return 0; return 0;
} }
}; };
Lexer.prototype.newlineToken = function() {
Lexer.prototype.newlineToken = function(offset) {
while (this.value() === ';') {
this.tokens.pop();
}
if (this.tag() !== 'TERMINATOR') { if (this.tag() !== 'TERMINATOR') {
this.token('TERMINATOR', '\n', offset, 0); this.token('TERMINATOR', '\n');
} }
return this; return this;
}; };
Lexer.prototype.suppressNewlines = function() { Lexer.prototype.suppressNewlines = function() {
if (this.value() === '\\') { if (this.value() === '\\') {
this.tokens.pop(); this.tokens.pop();
} }
return this; return this;
}; };
Lexer.prototype.literalToken = function() { Lexer.prototype.literalToken = function() {
var match, prev, tag, value, _ref2, _ref3, _ref4, _ref5; var match, prev, tag, value, _ref2, _ref3, _ref4, _ref5;
if (match = OPERATOR.exec(this.chunk)) { if (match = OPERATOR.exec(this.chunk)) {
@ -467,7 +380,7 @@ define(function(require, exports, module) {
prev = last(this.tokens); prev = last(this.tokens);
if (value === '=' && prev) { if (value === '=' && prev) {
if (!prev[1].reserved && (_ref2 = prev[1], __indexOf.call(JS_FORBIDDEN, _ref2) >= 0)) { if (!prev[1].reserved && (_ref2 = prev[1], __indexOf.call(JS_FORBIDDEN, _ref2) >= 0)) {
this.error("reserved word \"" + (this.value()) + "\" can't be assigned"); this.assignmentError();
} }
if ((_ref3 = prev[1]) === '||' || _ref3 === '&&') { if ((_ref3 = prev[1]) === '||' || _ref3 === '&&') {
prev[0] = 'COMPOUND_ASSIGN'; prev[0] = 'COMPOUND_ASSIGN';
@ -476,7 +389,6 @@ define(function(require, exports, module) {
} }
} }
if (value === ';') { if (value === ';') {
this.seenFor = false;
tag = 'TERMINATOR'; tag = 'TERMINATOR';
} else if (__indexOf.call(MATH, value) >= 0) { } else if (__indexOf.call(MATH, value) >= 0) {
tag = 'MATH'; tag = 'MATH';
@ -501,32 +413,23 @@ define(function(require, exports, module) {
switch (prev[0]) { switch (prev[0]) {
case '?': case '?':
prev[0] = 'INDEX_SOAK'; prev[0] = 'INDEX_SOAK';
break;
case '::':
prev[0] = 'INDEX_PROTO';
} }
} }
} }
switch (value) {
case '(':
case '{':
case '[':
this.ends.push(INVERSES[value]);
break;
case ')':
case '}':
case ']':
this.pair(value);
}
this.token(tag, value); this.token(tag, value);
return value.length; return value.length;
}; };
Lexer.prototype.sanitizeHeredoc = function(doc, options) { Lexer.prototype.sanitizeHeredoc = function(doc, options) {
var attempt, herecomment, indent, match, _ref2; var attempt, herecomment, indent, match, _ref2;
indent = options.indent, herecomment = options.herecomment; indent = options.indent, herecomment = options.herecomment;
if (herecomment) { if (herecomment) {
if (HEREDOC_ILLEGAL.test(doc)) { if (HEREDOC_ILLEGAL.test(doc)) {
this.error("block comment cannot contain \"*/\", starting"); throw new Error("block comment cannot contain \"*/\", starting on line " + (this.line + 1));
} }
if (doc.indexOf('\n') < 0) { if (doc.indexOf('\n') <= 0) {
return doc; return doc;
} }
} else { } else {
@ -545,7 +448,6 @@ define(function(require, exports, module) {
} }
return doc; return doc;
}; };
Lexer.prototype.tagParameters = function() { Lexer.prototype.tagParameters = function() {
var i, stack, tok, tokens; var i, stack, tok, tokens;
if (this.tag() !== ')') { if (this.tag() !== ')') {
@ -567,43 +469,38 @@ define(function(require, exports, module) {
} else if (tok[0] === '(') { } else if (tok[0] === '(') {
tok[0] = 'PARAM_START'; tok[0] = 'PARAM_START';
return this; return this;
} else {
return this;
} }
} }
} }
return this; return this;
}; };
Lexer.prototype.closeIndentation = function() { Lexer.prototype.closeIndentation = function() {
return this.outdentToken(this.indent); return this.outdentToken(this.indent);
}; };
Lexer.prototype.identifierError = function(word) {
throw SyntaxError("Reserved word \"" + word + "\" on line " + (this.line + 1));
};
Lexer.prototype.assignmentError = function() {
throw SyntaxError("Reserved word \"" + (this.value()) + "\" on line " + (this.line + 1) + " can't be assigned");
};
Lexer.prototype.balancedString = function(str, end) { Lexer.prototype.balancedString = function(str, end) {
var continueCount, i, letter, match, prev, stack, _i, _ref2; var i, letter, prev, stack, _ref2;
continueCount = 0;
stack = [end]; stack = [end];
for (i = _i = 1, _ref2 = str.length; 1 <= _ref2 ? _i < _ref2 : _i > _ref2; i = 1 <= _ref2 ? ++_i : --_i) { for (i = 1, _ref2 = str.length; 1 <= _ref2 ? i < _ref2 : i > _ref2; 1 <= _ref2 ? i++ : i--) {
if (continueCount) {
--continueCount;
continue;
}
switch (letter = str.charAt(i)) { switch (letter = str.charAt(i)) {
case '\\': case '\\':
++continueCount; i++;
continue; continue;
case end: case end:
stack.pop(); stack.pop();
if (!stack.length) { if (!stack.length) {
return str.slice(0, +i + 1 || 9e9); return str.slice(0, i + 1);
} }
end = stack[stack.length - 1]; end = stack[stack.length - 1];
continue; continue;
} }
if (end === '}' && (letter === '"' || letter === "'")) { if (end === '}' && (letter === '"' || letter === "'")) {
stack.push(end = 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 === '{') { } else if (end === '}' && letter === '{') {
stack.push(end = '}'); stack.push(end = '}');
} else if (end === '"' && prev === '#' && letter === '{') { } else if (end === '"' && prev === '#' && letter === '{') {
@ -611,18 +508,14 @@ define(function(require, exports, module) {
} }
prev = letter; prev = letter;
} }
return this.error("missing " + (stack.pop()) + ", starting"); throw new Error("missing " + (stack.pop()) + ", starting on line " + (this.line + 1));
}; };
Lexer.prototype.interpolateString = function(str, options) { Lexer.prototype.interpolateString = function(str, options) {
var column, expr, heredoc, i, inner, interpolated, len, letter, lexedLength, line, locationToken, nested, offsetInChunk, pi, plusToken, popped, regex, rparen, strOffset, tag, token, tokens, value, _i, _len, _ref2, _ref3, _ref4; var expr, heredoc, i, inner, interpolated, len, letter, nested, pi, regex, tag, tokens, value, _len, _ref2, _ref3, _ref4;
if (options == null) { if (options == null) {
options = {}; options = {};
} }
heredoc = options.heredoc, regex = options.regex, offsetInChunk = options.offsetInChunk, strOffset = options.strOffset, lexedLength = options.lexedLength; heredoc = options.heredoc, regex = options.regex;
offsetInChunk = offsetInChunk || 0;
strOffset = strOffset || 0;
lexedLength = lexedLength || str.length;
tokens = []; tokens = [];
pi = 0; pi = 0;
i = -1; i = -1;
@ -635,24 +528,22 @@ define(function(require, exports, module) {
continue; continue;
} }
if (pi < i) { if (pi < i) {
tokens.push(this.makeToken('NEOSTRING', str.slice(pi, i), strOffset + pi)); tokens.push(['NEOSTRING', str.slice(pi, i)]);
} }
inner = expr.slice(1, -1); inner = expr.slice(1, -1);
if (inner.length) { if (inner.length) {
_ref2 = this.getLineAndColumnFromChunk(strOffset + i + 1), line = _ref2[0], column = _ref2[1];
nested = new Lexer().tokenize(inner, { nested = new Lexer().tokenize(inner, {
line: line, line: this.line,
column: column,
rewrite: false rewrite: false
}); });
popped = nested.pop(); nested.pop();
if (((_ref3 = nested[0]) != null ? _ref3[0] : void 0) === 'TERMINATOR') { if (((_ref2 = nested[0]) != null ? _ref2[0] : void 0) === 'TERMINATOR') {
popped = nested.shift(); nested.shift();
} }
if (len = nested.length) { if (len = nested.length) {
if (len > 1) { if (len > 1) {
nested.unshift(this.makeToken('(', '(', strOffset + i + 1, 0)); nested.unshift(['(', '(']);
nested.push(this.makeToken(')', ')', strOffset + i + 1 + inner.length, 0)); nested.push([')', ')']);
} }
tokens.push(['TOKENS', nested]); tokens.push(['TOKENS', nested]);
} }
@ -661,150 +552,60 @@ define(function(require, exports, module) {
pi = i + 1; pi = i + 1;
} }
if ((i > pi && pi < str.length)) { if ((i > pi && pi < str.length)) {
tokens.push(this.makeToken('NEOSTRING', str.slice(pi), strOffset + pi)); tokens.push(['NEOSTRING', str.slice(pi)]);
} }
if (regex) { if (regex) {
return tokens; return tokens;
} }
if (!tokens.length) { if (!tokens.length) {
return this.token('STRING', '""', offsetInChunk, lexedLength); return this.token('STRING', '""');
} }
if (tokens[0][0] !== 'NEOSTRING') { if (tokens[0][0] !== 'NEOSTRING') {
tokens.unshift(this.makeToken('NEOSTRING', '', offsetInChunk)); tokens.unshift(['', '']);
} }
if (interpolated = tokens.length > 1) { if (interpolated = tokens.length > 1) {
this.token('(', '(', offsetInChunk, 0); this.token('(', '(');
} }
for (i = _i = 0, _len = tokens.length; _i < _len; i = ++_i) { for (i = 0, _len = tokens.length; i < _len; i++) {
token = tokens[i]; _ref3 = tokens[i], tag = _ref3[0], value = _ref3[1];
tag = token[0], value = token[1];
if (i) { if (i) {
if (i) { this.token('+', '+');
plusToken = this.token('+', '+');
}
locationToken = tag === 'TOKENS' ? value[0] : token;
plusToken[2] = {
first_line: locationToken[2].first_line,
first_column: locationToken[2].first_column,
last_line: locationToken[2].first_line,
last_column: locationToken[2].first_column
};
} }
if (tag === 'TOKENS') { if (tag === 'TOKENS') {
(_ref4 = this.tokens).push.apply(_ref4, value); (_ref4 = this.tokens).push.apply(_ref4, value);
} else if (tag === 'NEOSTRING') {
token[0] = 'STRING';
token[1] = this.makeString(value, '"', heredoc);
this.tokens.push(token);
} else { } else {
this.error("Unexpected " + tag); this.token('STRING', this.makeString(value, '"', heredoc));
} }
} }
if (interpolated) { if (interpolated) {
rparen = this.makeToken(')', ')', offsetInChunk + lexedLength, 0); this.token(')', ')');
rparen.stringEnd = true;
this.tokens.push(rparen);
} }
return tokens; return tokens;
}; };
Lexer.prototype.token = function(tag, value) {
Lexer.prototype.pair = function(tag) { return this.tokens.push([tag, value, this.line]);
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.getLineAndColumnFromChunk = function(offset) {
var column, lineCount, lines, string;
if (offset === 0) {
return [this.chunkLine, this.chunkColumn];
}
if (offset >= this.chunk.length) {
string = this.chunk;
} else {
string = this.chunk.slice(0, +(offset - 1) + 1 || 9e9);
}
lineCount = count(string, '\n');
column = this.chunkColumn;
if (lineCount > 0) {
lines = string.split('\n');
column = last(lines).length;
} else {
column += string.length;
}
return [this.chunkLine + lineCount, column];
};
Lexer.prototype.makeToken = function(tag, value, offsetInChunk, length) {
var lastCharacter, locationData, token, _ref2, _ref3;
if (offsetInChunk == null) {
offsetInChunk = 0;
}
if (length == null) {
length = value.length;
}
locationData = {};
_ref2 = this.getLineAndColumnFromChunk(offsetInChunk), locationData.first_line = _ref2[0], locationData.first_column = _ref2[1];
lastCharacter = Math.max(0, length - 1);
_ref3 = this.getLineAndColumnFromChunk(offsetInChunk + lastCharacter), locationData.last_line = _ref3[0], locationData.last_column = _ref3[1];
token = [tag, value, locationData];
return token;
};
Lexer.prototype.token = function(tag, value, offsetInChunk, length) {
var token;
token = this.makeToken(tag, value, offsetInChunk, length);
this.tokens.push(token);
return token;
};
Lexer.prototype.tag = function(index, tag) { Lexer.prototype.tag = function(index, tag) {
var tok; var tok;
return (tok = last(this.tokens, index)) && (tag ? tok[0] = tag : tok[0]); return (tok = last(this.tokens, index)) && (tag ? tok[0] = tag : tok[0]);
}; };
Lexer.prototype.value = function(index, val) { Lexer.prototype.value = function(index, val) {
var tok; var tok;
return (tok = last(this.tokens, index)) && (val ? tok[1] = val : tok[1]); return (tok = last(this.tokens, index)) && (val ? tok[1] = val : tok[1]);
}; };
Lexer.prototype.unfinished = function() { Lexer.prototype.unfinished = function() {
var _ref2; var prev, value;
return LINE_CONTINUER.test(this.chunk) || ((_ref2 = this.tag()) === '\\' || _ref2 === '.' || _ref2 === '?.' || _ref2 === '?::' || _ref2 === 'UNARY' || _ref2 === 'MATH' || _ref2 === '+' || _ref2 === '-' || _ref2 === 'SHIFT' || _ref2 === 'RELATION' || _ref2 === 'COMPARE' || _ref2 === 'LOGIC' || _ref2 === 'THROW' || _ref2 === 'EXTENDS'); return LINE_CONTINUER.test(this.chunk) || (prev = last(this.tokens, 1)) && prev[0] !== '.' && (value = this.value()) && !value.reserved && NO_NEWLINE.test(value) && !CODE.test(value) && !ASSIGNED.test(this.chunk);
}; };
Lexer.prototype.removeNewlines = function(str) {
return str.replace(/^\s*\n\s*/, '').replace(/([^\\]|\\\\)\s*\n\s*$/, '$1');
};
Lexer.prototype.escapeLines = function(str, heredoc) { Lexer.prototype.escapeLines = function(str, heredoc) {
str = str.replace(/\\[^\S\n]*(\n|\\)\s*/g, function(escaped, character) { return str.replace(MULTILINER, heredoc ? '\\n' : '');
if (character === '\n') {
return '';
} else {
return escaped;
}
});
if (heredoc) {
return str.replace(MULTILINER, '\\n');
} else {
return str.replace(/\s*\n\s*/g, ' ');
}
}; };
Lexer.prototype.makeString = function(body, quote, heredoc) { Lexer.prototype.makeString = function(body, quote, heredoc) {
if (!body) { if (!body) {
return quote + quote; return quote + quote;
} }
body = body.replace(RegExp("\\\\(" + quote + "|\\\\)", "g"), function(match, contents) { body = body.replace(/\\([\s\S])/g, function(match, contents) {
if (contents === quote) { if (contents === '\n' || contents === quote) {
return contents; return contents;
} else { } else {
return match; return match;
@ -813,27 +614,10 @@ define(function(require, exports, module) {
body = body.replace(RegExp("" + quote, "g"), '\\$&'); body = body.replace(RegExp("" + quote, "g"), '\\$&');
return quote + this.escapeLines(body, heredoc) + quote; return quote + this.escapeLines(body, heredoc) + quote;
}; };
Lexer.prototype.error = function(message, offset) {
var first_column, first_line, _ref2;
if (offset == null) {
offset = 0;
}
_ref2 = this.getLineAndColumnFromChunk(offset), first_line = _ref2[0], first_column = _ref2[1];
return throwSyntaxError(message, {
first_line: first_line,
first_column: first_column
});
};
return Lexer; 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']; 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_KEYWORDS = ['undefined', 'then', 'unless', 'until', 'loop', 'of', 'by', 'when'];
COFFEE_ALIAS_MAP = { COFFEE_ALIAS_MAP = {
and: '&&', and: '&&',
or: '||', or: '||',
@ -845,7 +629,6 @@ define(function(require, exports, module) {
on: 'true', on: 'true',
off: 'false' off: 'false'
}; };
COFFEE_ALIASES = (function() { COFFEE_ALIASES = (function() {
var _results; var _results;
_results = []; _results = [];
@ -854,82 +637,41 @@ define(function(require, exports, module) {
} }
return _results; return _results;
})(); })();
COFFEE_KEYWORDS = COFFEE_KEYWORDS.concat(COFFEE_ALIASES); 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'];
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']; JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED);
exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS);
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;
BOM = 65279;
IDENTIFIER = /^([$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*)([^\n\S]*:(?!:))?/; IDENTIFIER = /^([$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*)([^\n\S]*:(?!:))?/;
NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?/i;
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})/;
HEREDOC = /^("""|''')((?:\\[\s\S]|[^\\])*?)(?:\n[^\n\S]*)?\1/;
OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?(\.|::)|\.{2,3})/;
WHITESPACE = /^[^\n\S]+/; WHITESPACE = /^[^\n\S]+/;
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/;
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|###$)|^(?:\s*#(?!##[^#]).*)+/;
CODE = /^[-=]>/; CODE = /^[-=]>/;
MULTI_DENT = /^(?:\n[^\n\S]*)+/; MULTI_DENT = /^(?:\n[^\n\S]*)+/;
SIMPLESTR = /^'[^\\']*(?:\\.[^\\']*)*'/;
SIMPLESTR = /^'[^\\']*(?:\\[\s\S][^\\']*)*'/;
JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/; JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/;
REGEX = /^\/(?![\s=])[^[\/\n\\]*(?:(?:\\[\s\S]|\[[^\]\n\\]*(?:\\[\s\S][^\]\n\\]*)*])[^[\/\n\\]*)*\/[imgy]{0,4}(?!\w)/;
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;
HEREGEX = /^\/{3}((?:\\?[\s\S])+?)\/{3}([imgy]{0,4})(?!\w)/;
HEREGEX_OMIT = /((?:\\\\)+)|\\(\s|\/)|\s+(?:#.*)?/g;
MULTILINER = /\n/g; MULTILINER = /\n/g;
HEREDOC_INDENT = /\n+([^\n\S]*)/g; HEREDOC_INDENT = /\n+([^\n\S]*)/g;
HEREDOC_ILLEGAL = /\*\//; HEREDOC_ILLEGAL = /\*\//;
ASSIGNED = /^\s*@?([$A-Za-z_][$\w\x7f-\uffff]*|['"].*['"])[^\n\S]*?[:=][^:=>]/;
LINE_CONTINUER = /^\s*(?:,|\??\.(?![.\d])|::)/; LINE_CONTINUER = /^\s*(?:,|\??\.(?![.\d])|::)/;
TRAILING_SPACES = /\s+$/; TRAILING_SPACES = /\s+$/;
NO_NEWLINE = /^(?:[-+*&|\/%=<>!.\\][<>=&|]*|and|or|is(?:nt)?|n(?:ot|ew)|delete|typeof|instanceof)$/;
COMPOUND_ASSIGN = ['-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|=']; COMPOUND_ASSIGN = ['-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|='];
UNARY = ['!', '~', 'NEW', 'TYPEOF', 'DELETE', 'DO']; UNARY = ['!', '~', 'NEW', 'TYPEOF', 'DELETE', 'DO'];
LOGIC = ['&&', '||', '&', '|', '^']; LOGIC = ['&&', '||', '&', '|', '^'];
SHIFT = ['<<', '>>', '>>>']; SHIFT = ['<<', '>>', '>>>'];
COMPARE = ['==', '!=', '<', '>', '<=', '>=']; COMPARE = ['==', '!=', '<', '>', '<=', '>='];
MATH = ['*', '/', '%']; MATH = ['*', '/', '%'];
RELATION = ['IN', 'OF', 'INSTANCEOF']; RELATION = ['IN', 'OF', 'INSTANCEOF'];
BOOL = ['TRUE', 'FALSE', 'NULL', 'UNDEFINED'];
BOOL = ['TRUE', 'FALSE']; NOT_REGEX = ['NUMBER', 'REGEX', 'BOOL', '++', '--', ']'];
NOT_SPACED_REGEX = NOT_REGEX.concat(')', '}', 'THIS', 'IDENTIFIER', 'STRING');
NOT_REGEX = ['NUMBER', 'REGEX', 'BOOL', 'NULL', 'UNDEFINED', '++', '--'];
NOT_SPACED_REGEX = NOT_REGEX.concat(')', '}', 'THIS', 'IDENTIFIER', 'STRING', ']');
CALLABLE = ['IDENTIFIER', 'STRING', 'REGEX', ')', ']', '}', '?', '::', '@', 'THIS', 'SUPER']; CALLABLE = ['IDENTIFIER', 'STRING', 'REGEX', ')', ']', '}', '?', '::', '@', 'THIS', 'SUPER'];
INDEXABLE = CALLABLE.concat('NUMBER', 'BOOL');
INDEXABLE = CALLABLE.concat('NUMBER', 'BOOL', 'NULL', 'UNDEFINED');
LINE_BREAK = ['INDENT', 'OUTDENT', 'TERMINATOR']; LINE_BREAK = ['INDENT', 'OUTDENT', 'TERMINATOR'];
});
});

2301
ace/mode/coffee/nodes.js Normal file

File diff suppressed because it is too large Load diff

685
ace/mode/coffee/parser.js Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,67 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
if (typeof process !== "undefined") {
require("../../../support/paths");
}
define(function(require, exports, module) {
var assert = require("ace/test/assertions");
var coffee = require("ace/mode/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();
}

389
ace/mode/coffee/rewriter.js Normal file
View file

@ -0,0 +1,389 @@
/**
* Copyright (c) 2011 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) {
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;
var __indexOf = Array.prototype.indexOf || function(item) {
for (var i = 0, l = this.length; i < l; i++) {
if (this[i] === item) return i;
}
return -1;
}, __slice = Array.prototype.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();
this.ensureBalance(BALANCED_PAIRS);
this.rewriteClosingParens();
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, _ref2;
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 (_ref2 = token[0], __indexOf.call(EXPRESSION_END, _ref2) >= 0) {
levels -= 1;
}
i += 1;
}
return i - 1;
};
Rewriter.prototype.removeLeadingNewlines = function() {
var i, tag, _len, _ref;
_ref = this.tokens;
for (i = 0, _len = _ref.length; i < _len; 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, stack, start, startIndent;
stack = [];
start = null;
startIndent = 0;
condition = function(token, i) {
var one, tag, three, two, _ref, _ref2;
_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];
return ((tag === 'TERMINATOR' || tag === 'OUTDENT') && !((two != null ? two[0] : void 0) === ':' || (one != null ? one[0] : void 0) === '@' && (three != null ? three[0] : void 0) === ':')) || (tag === ',' && one && ((_ref2 = one[0]) !== 'IDENTIFIER' && _ref2 !== 'NUMBER' && _ref2 !== 'STRING' && _ref2 !== '@' && _ref2 !== 'TERMINATOR' && _ref2 !== 'OUTDENT'));
};
action = function(token, i) {
var tok;
tok = ['}', '}', token[2]];
tok.generated = true;
return this.tokens.splice(i, 0, tok);
};
return this.scanTokens(function(token, i, tokens) {
var ago, idx, tag, tok, value, _ref, _ref2;
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)) === ':' || ((_ref2 = stack[stack.length - 1]) != null ? _ref2[0] : void 0) !== '{'))) {
return 1;
}
stack.push(['{']);
idx = ago === '@' ? i - 2 : i - 1;
while (this.tag(idx - 2) === 'HERECOMMENT') {
idx -= 2;
}
value = new String('{');
value.generated = true;
tok = ['{', value, token[2]];
tok.generated = true;
tokens.splice(idx, 0, tok);
this.detectEnd(i + 2, condition, action);
return 2;
});
};
Rewriter.prototype.addImplicitParentheses = function() {
var action, noCall;
noCall = false;
action = function(token, i) {
var idx;
idx = token[0] === 'OUTDENT' ? i + 1 : i;
return this.tokens.splice(idx, 0, ['CALL_END', ')', token[2]]);
};
return this.scanTokens(function(token, i, tokens) {
var callObject, current, next, prev, seenControl, seenSingle, tag, _ref, _ref2, _ref3;
tag = token[0];
if (tag === 'CLASS' || tag === 'IF') {
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 && (_ref2 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref2) >= 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 || (_ref3 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref3) >= 0)) && (__indexOf.call(IMPLICIT_CALL, tag) >= 0 || !(token.spaced || token.newLine) && __indexOf.call(IMPLICIT_UNSPACED_CALL, tag) >= 0))) {
return 1;
}
tokens.splice(i, 0, ['CALL_START', '(', token[2]]);
this.detectEnd(i + 1, function(token, i) {
var post, _ref4;
tag = token[0];
if (!seenSingle && token.fromThen) {
return true;
}
if (tag === 'IF' || tag === 'ELSE' || tag === 'CATCH' || tag === '->' || tag === '=>') {
seenSingle = true;
}
if (tag === 'IF' || tag === 'ELSE' || tag === 'SWITCH' || tag === 'TRY') {
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' || (this.tag(i - 2) !== 'CLASS' && (_ref4 = this.tag(i - 1), __indexOf.call(IMPLICIT_BLOCK, _ref4) < 0) && !((post = this.tokens[i + 1]) && post.generated && post[0] === '{')));
}, action);
if (prev[0] === '?') {
prev[0] = 'FUNC_EXIST';
}
return 2;
});
};
Rewriter.prototype.addImplicitIndentation = function() {
return this.scanTokens(function(token, i, tokens) {
var action, condition, indent, outdent, starter, tag, _ref, _ref2;
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;
_ref2 = this.indentation(token), indent = _ref2[0], outdent = _ref2[1];
if (starter === 'THEN') {
indent.fromThen = true;
}
indent.generated = outdent.generated = true;
tokens.splice(i + 1, 0, indent);
condition = function(token, i) {
var _ref3;
return token[1] !== ';' && (_ref3 = token[0], __indexOf.call(SINGLE_CLOSERS, _ref3) >= 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);
};
this.detectEnd(i + 2, condition, action);
if (tag === 'THEN') {
tokens.splice(i, 1);
}
return 1;
}
return 1;
});
};
Rewriter.prototype.tagPostfixConditionals = function() {
var condition;
condition = function(token, i) {
var _ref;
return (_ref = token[0]) === 'TERMINATOR' || _ref === 'INDENT';
};
return this.scanTokens(function(token, i) {
var original;
if (token[0] !== 'IF') {
return 1;
}
original = token;
this.detectEnd(i + 1, condition, function(token, i) {
if (token[0] !== 'INDENT') {
return original[0] = 'POST_' + original[0];
}
});
return 1;
});
};
Rewriter.prototype.ensureBalance = function(pairs) {
var close, level, levels, open, openLine, tag, token, _i, _j, _len, _len2, _ref, _ref2;
levels = {};
openLine = {};
_ref = this.tokens;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
token = _ref[_i];
tag = token[0];
for (_j = 0, _len2 = pairs.length; _j < _len2; _j++) {
_ref2 = pairs[_j], open = _ref2[0], close = _ref2[1];
levels[open] |= 0;
if (tag === open) {
if (levels[open]++ === 0) {
openLine[open] = token[2];
}
} else if (tag === close && --levels[open] < 0) {
throw Error("too many " + token[1] + " on line " + (token[2] + 1));
}
}
}
for (open in levels) {
level = levels[open];
if (level > 0) {
throw Error("unclosed " + open + " on line " + (openLine[open] + 1));
}
}
return this;
};
Rewriter.prototype.rewriteClosingParens = function() {
var debt, key, stack;
stack = [];
debt = {};
for (key in INVERSES) {
debt[key] = 0;
}
return this.scanTokens(function(token, i, tokens) {
var inv, match, mtag, oppos, tag, val, _ref;
if (_ref = (tag = token[0]), __indexOf.call(EXPRESSION_START, _ref) >= 0) {
stack.push(token);
return 1;
}
if (__indexOf.call(EXPRESSION_END, tag) < 0) {
return 1;
}
if (debt[inv = INVERSES[tag]] > 0) {
debt[inv] -= 1;
tokens.splice(i, 1);
return 0;
}
match = stack.pop();
mtag = match[0];
oppos = INVERSES[mtag];
if (tag === oppos) {
return 1;
}
debt[mtag] += 1;
val = [oppos, mtag === 'INDENT' ? match[1] : oppos];
if (this.tag(i + 2) === mtag) {
tokens.splice(i + 3, 0, val);
stack.push(match);
} else {
tokens.splice(i, 0, val);
}
return 1;
});
};
Rewriter.prototype.indentation = function(token) {
return [['INDENT', 2, token[2]], ['OUTDENT', 2, token[2]]];
};
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']];
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', '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'];
});

View file

@ -1,6 +1,6 @@
/** /**
* Copyright (c) 2009-2013 Jeremy Ashkenas * Copyright (c) 2011 Jeremy Ashkenas
* *
* Permission is hereby granted, free of charge, to any person * Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation * obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without * files (the "Software"), to deal in the Software without
@ -21,19 +21,13 @@
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE. * OTHER DEALINGS IN THE SOFTWARE.
*
*/ */
define(function(require, exports, module) { define(function(require, exports, module) {
// Generated by CoffeeScript 1.6.3
var Scope, extend, last, _ref; var Scope, extend, last, _ref;
_ref = require('ace/mode/coffee/helpers'), extend = _ref.extend, last = _ref.last;
_ref = require('./helpers'), extend = _ref.extend, last = _ref.last;
exports.Scope = Scope = (function() { exports.Scope = Scope = (function() {
Scope.root = null; Scope.root = null;
function Scope(parent, expressions, method) { function Scope(parent, expressions, method) {
this.parent = parent; this.parent = parent;
this.expressions = expressions; this.expressions = expressions;
@ -49,13 +43,13 @@ define(function(require, exports, module) {
Scope.root = this; Scope.root = this;
} }
} }
Scope.prototype.add = function(name, type, immediate) { Scope.prototype.add = function(name, type, immediate) {
var pos;
if (this.shared && !immediate) { if (this.shared && !immediate) {
return this.parent.add(name, type, immediate); return this.parent.add(name, type, immediate);
} }
if (Object.prototype.hasOwnProperty.call(this.positions, name)) { if (typeof (pos = this.positions[name]) === 'number') {
return this.variables[this.positions[name]].type = type; return this.variables[pos].type = type;
} else { } else {
return this.positions[name] = this.variables.push({ return this.positions[name] = this.variables.push({
name: name, name: name,
@ -63,112 +57,89 @@ define(function(require, exports, module) {
}) - 1; }) - 1;
} }
}; };
Scope.prototype.find = function(name, options) {
Scope.prototype.namedMethod = function() { if (this.check(name, options)) {
var _ref1;
if (((_ref1 = this.method) != null ? _ref1.name : void 0) || !this.parent) {
return this.method;
}
return this.parent.namedMethod();
};
Scope.prototype.find = function(name) {
if (this.check(name)) {
return true; return true;
} }
this.add(name, 'var'); this.add(name, 'var');
return false; return false;
}; };
Scope.prototype.parameter = function(name) { Scope.prototype.parameter = function(name) {
if (this.shared && this.parent.check(name, true)) { if (this.shared && this.parent.check(name, true)) {
return; return;
} }
return this.add(name, 'param'); return this.add(name, 'param');
}; };
Scope.prototype.check = function(name, immediate) {
Scope.prototype.check = function(name) { var found, _ref2;
var _ref1; found = !!this.type(name);
return !!(this.type(name) || ((_ref1 = this.parent) != null ? _ref1.check(name) : void 0)); if (found || immediate) {
return found;
}
return !!((_ref2 = this.parent) != null ? _ref2.check(name) : void 0);
}; };
Scope.prototype.temporary = function(name, index) { Scope.prototype.temporary = function(name, index) {
if (name.length > 1) { if (name.length > 1) {
return '_' + name + (index > 1 ? index - 1 : ''); return '_' + name + (index > 1 ? index : '');
} else { } else {
return '_' + (index + parseInt(name, 36)).toString(36).replace(/\d/g, 'a'); return '_' + (index + parseInt(name, 36)).toString(36).replace(/\d/g, 'a');
} }
}; };
Scope.prototype.type = function(name) { Scope.prototype.type = function(name) {
var v, _i, _len, _ref1; var v, _i, _len, _ref2;
_ref1 = this.variables; _ref2 = this.variables;
for (_i = 0, _len = _ref1.length; _i < _len; _i++) { for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
v = _ref1[_i]; v = _ref2[_i];
if (v.name === name) { if (v.name === name) {
return v.type; return v.type;
} }
} }
return null; return null;
}; };
Scope.prototype.freeVariable = function(type) {
Scope.prototype.freeVariable = function(name, reserve) {
var index, temp; var index, temp;
if (reserve == null) {
reserve = true;
}
index = 0; index = 0;
while (this.check((temp = this.temporary(name, index)))) { while (this.check((temp = this.temporary(type, index)))) {
index++; index++;
} }
if (reserve) { this.add(temp, 'var', true);
this.add(temp, 'var', true);
}
return temp; return temp;
}; };
Scope.prototype.assign = function(name, value) { Scope.prototype.assign = function(name, value) {
this.add(name, { this.add(name, {
value: value, value: value,
assigned: true assigned: true
}, true); });
return this.hasAssignments = true; return this.hasAssignments = true;
}; };
Scope.prototype.hasDeclarations = function() { Scope.prototype.hasDeclarations = function() {
return !!this.declaredVariables().length; return !!this.declaredVariables().length;
}; };
Scope.prototype.declaredVariables = function() { Scope.prototype.declaredVariables = function() {
var realVars, tempVars, v, _i, _len, _ref1; var realVars, tempVars, v, _i, _len, _ref2;
realVars = []; realVars = [];
tempVars = []; tempVars = [];
_ref1 = this.variables; _ref2 = this.variables;
for (_i = 0, _len = _ref1.length; _i < _len; _i++) { for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
v = _ref1[_i]; v = _ref2[_i];
if (v.type === 'var') { if (v.type === 'var') {
(v.name.charAt(0) === '_' ? tempVars : realVars).push(v.name); (v.name.charAt(0) === '_' ? tempVars : realVars).push(v.name);
} }
} }
return realVars.sort().concat(tempVars.sort()); return realVars.sort().concat(tempVars.sort());
}; };
Scope.prototype.assignedVariables = function() { Scope.prototype.assignedVariables = function() {
var v, _i, _len, _ref1, _results; var v, _i, _len, _ref2, _results;
_ref1 = this.variables; _ref2 = this.variables;
_results = []; _results = [];
for (_i = 0, _len = _ref1.length; _i < _len; _i++) { for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
v = _ref1[_i]; v = _ref2[_i];
if (v.type.assigned) { if (v.type.assigned) {
_results.push("" + v.name + " = " + v.type.value); _results.push("" + v.name + " = " + v.type.value);
} }
} }
return _results; return _results;
}; };
return Scope; return Scope;
})(); })();
});
});

View file

@ -0,0 +1,196 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Satoshi Murakami <murky.satyr AT gmail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
require("ace/lib/oop").inherits(
CoffeeHighlightRules,
require("ace/mode/text_highlight_rules").TextHighlightRules
);
function CoffeeHighlightRules() {
var identifier = "[$A-Za-z_\\x7f-\\uffff][$\\w\\x7f-\\uffff]*";
var keywordend = "(?![$\\w]|\\s*:)";
var stringfill = {
token : "string",
merge : true,
regex : ".+"
};
this.$rules = {
start : [
{
token : "identifier",
regex : "(?:@|(?:\\.|::)\\s*)" + identifier
}, {
token : "keyword",
regex : "(?:t(?:h(?:is|row|en)|ry|ypeof)|s(?:uper|witch)|return|b(?:reak|y)|c(?:ontinue|atch|lass)|i(?:n(?:stanceof)?|s(?:nt)?|f)|e(?:lse|xtends)|f(?:or (?:own)?|inally|unction)|wh(?:ile|en)|n(?:ew|ot?)|d(?:e(?:lete|bugger)|o)|loop|o(?:ff?|[rn])|un(?:less|til)|and|yes)"
+ keywordend
}, {
token : "constant.language",
regex : "(?:true|false|null|undefined)" + keywordend
}, {
token : "invalid.illegal",
regex : "(?:c(?:ase|onst)|default|function|v(?:ar|oid)|with|e(?:num|xport)|i(?:mplements|nterface)|let|p(?:ackage|r(?:ivate|otected)|ublic)|static|yield|__(?:hasProp|extends|slice|bind|indexOf))"
+ keywordend
}, {
token : "language.support.class",
regex : "(?:Array|Boolean|Date|Function|Number|Object|R(?:e(?:gExp|ferenceError)|angeError)|S(?:tring|yntaxError)|E(?:rror|valError)|TypeError|URIError)"
+ keywordend
}, {
token : "language.support.function",
regex : "(?:Math|JSON|is(?:NaN|Finite)|parse(?:Int|Float)|encodeURI(?:Component)?|decodeURI(?:Component)?)"
+ keywordend
}, {
token : "identifier",
regex : identifier
}, {
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\\\\]*(?: (?:\\\\.|\\[[^\\]\\n\\\\]*(?:\\\\.[^\\]\\n\\\\]*)*\\])[^[/\\n\\\\]*)*/[imgy]{0,4}(?!\\w)"
}, {
token : "comment",
merge : true,
regex : "###(?!#)",
next : "comment"
}, {
token : "comment",
regex : "#.*"
}, {
token : "lparen",
regex : "[({[]"
}, {
token : "rparen",
regex : "[\\]})]"
}, {
token : "keyword.operator",
regex : "\\S+"
}, {
token : "text",
regex : "\\s+"
}],
qdoc : [{
token : "string",
regex : ".*?'''",
next : "start"
}, stringfill],
qqdoc : [{
token : "string",
regex : '.*?"""',
next : "start"
}, stringfill],
qstring : [{
token : "string",
regex : "[^\\\\']*(?:\\\\.[^\\\\']*)*'",
next : "start"
}, stringfill],
qqstring : [{
token : "string",
regex : '[^\\\\"]*(?:\\\\.[^\\\\"]*)*"',
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;
});

91
ace/mode/coffee_worker.js Normal file
View file

@ -0,0 +1,91 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var Mirror = require("ace/worker/mirror").Mirror;
var coffee = require("ace/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]) - 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]) - 1,
column: null,
text: e.message.replace(m[0], ""),
type: "error"
});
}
}
return;
}
this.sender.emit("ok");
};
}).call(Worker.prototype);
});

56
ace/mode/csharp.js Normal file
View file

@ -0,0 +1,56 @@
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var TextMode = require("ace/mode/text").Mode;
var Tokenizer = require("ace/tokenizer").Tokenizer;
var CSharpHighlightRules = require("ace/mode/csharp_highlight_rules").CSharpHighlightRules;
var MatchingBraceOutdent = require("ace/mode/matching_brace_outdent").MatchingBraceOutdent;
var CstyleBehaviour = require("ace/mode/behaviour/cstyle").CstyleBehaviour;
var Mode = function() {
this.$tokenizer = new Tokenizer(new CSharpHighlightRules().getRules());
this.$outdent = new MatchingBraceOutdent();
this.$behaviour = new CstyleBehaviour();
};
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;
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;
}
}
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;
});

View file

@ -1,26 +1,20 @@
define(function(require, exports, module) { define(function(require, exports, module) {
"use strict";
var oop = require("../lib/oop"); var oop = require("ace/lib/oop");
var lang = require("ace/lib/lang");
var DocCommentHighlightRules = require("ace/mode/doc_comment_highlight_rules").DocCommentHighlightRules;
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
var DocCommentHighlightRules = require("./doc_comment_highlight_rules").DocCommentHighlightRules; var CSharpHighlightRules = function() {
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
var keywords = lang.arrayToMap(
var HaxeHighlightRules = function() { ("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").split("|")
var keywords = (
"break|case|cast|catch|class|continue|default|else|enum|extends|for|function|if|implements|import|in|inline|interface|new|override|package|private|public|return|static|super|switch|this|throw|trace|try|typedef|untyped|var|while|Array|Void|Bool|Int|UInt|Float|Dynamic|String|List|Hash|IntHash|Error|Unknown|Type|Std"
); );
var buildinConstants = ( var buildinConstants = lang.arrayToMap(
"null|true|false" ("null|true|false").split("|")
); );
var keywordMapper = this.createKeywordMapper({
"variable.language": "this",
"keyword": keywords,
"constant.language": buildinConstants
}, "identifier");
// regexp must not have capturing parentheses. Use (?:) instead. // regexp must not have capturing parentheses. Use (?:) instead.
// regexps are ordered -> the first match is used // regexps are ordered -> the first match is used
@ -31,10 +25,11 @@ var HaxeHighlightRules = function() {
token : "comment", token : "comment",
regex : "\\/\\/.*$" regex : "\\/\\/.*$"
}, },
DocCommentHighlightRules.getStartRule("doc-start"), new DocCommentHighlightRules().getStartRule("doc-start"),
{ {
token : "comment", // multi line comment token : "comment", // multi line comment
regex : "\\/\\*", regex : "\\/\\*",
merge : true,
next : "comment" next : "comment"
}, { }, {
token : "string.regexp", token : "string.regexp",
@ -55,7 +50,16 @@ var HaxeHighlightRules = function() {
token : "constant.language.boolean", token : "constant.language.boolean",
regex : "(?:true|false)\\b" regex : "(?:true|false)\\b"
}, { }, {
token : keywordMapper, token : function(value) {
if (value == "this")
return "variable.language";
else if (keywords.hasOwnProperty(value))
return "keyword";
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
else
return "identifier";
},
// TODO: Unicode escape sequences // TODO: Unicode escape sequences
// TODO: Unicode identifiers // TODO: Unicode identifiers
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
@ -63,14 +67,11 @@ var HaxeHighlightRules = function() {
token : "keyword.operator", token : "keyword.operator",
regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)" regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)"
}, { }, {
token : "punctuation.operator", token : "lparen",
regex : "\\?|\\:|\\,|\\;|\\." regex : "[[({]"
}, { }, {
token : "paren.lparen", token : "rparen",
regex : "[[({<]" regex : "[\\])}]"
}, {
token : "paren.rparen",
regex : "[\\])}>]"
}, { }, {
token : "text", token : "text",
regex : "\\s+" regex : "\\s+"
@ -83,16 +84,17 @@ var HaxeHighlightRules = function() {
next : "start" next : "start"
}, { }, {
token : "comment", // comment spanning whole line token : "comment", // comment spanning whole line
merge : true,
regex : ".+" regex : ".+"
} }
] ]
}; };
this.embedRules(DocCommentHighlightRules, "doc-", this.embedRules(DocCommentHighlightRules, "doc-",
[ DocCommentHighlightRules.getEndRule("start") ]); [ new DocCommentHighlightRules().getEndRule("start") ]);
}; };
oop.inherits(HaxeHighlightRules, TextHighlightRules); oop.inherits(CSharpHighlightRules, TextHighlightRules);
exports.HaxeHighlightRules = HaxeHighlightRules; exports.CSharpHighlightRules = CSharpHighlightRules;
}); });

113
ace/mode/css.js Normal file
View file

@ -0,0 +1,113 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var TextMode = require("ace/mode/text").Mode;
var Tokenizer = require("ace/tokenizer").Tokenizer;
var CssHighlightRules = require("ace/mode/css_highlight_rules").CssHighlightRules;
var MatchingBraceOutdent = require("ace/mode/matching_brace_outdent").MatchingBraceOutdent;
var WorkerClient = require("ace/worker/worker_client").WorkerClient;
var Mode = function() {
this.$tokenizer = new Tokenizer(new CssHighlightRules().getRules());
this.$outdent = new MatchingBraceOutdent();
};
oop.inherits(Mode, TextMode);
(function() {
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 doc = session.getDocument();
var worker = new WorkerClient(["ace"], "worker-css.js", "ace/mode/css_worker", "Worker");
worker.call("setValue", [doc.getValue()]);
doc.on("change", function(e) {
e.range = {
start: e.data.range.start,
end: e.data.range.end
};
worker.emit("change", e);
});
worker.on("csslint", function(e) {
var errors = [];
e.data.forEach(function(message) {
errors.push({
row: message.line - 1,
column: message.col - 1,
text: message.message,
type: message.type,
lint: message
});
});
session.setAnnotations(errors);
});
};
}).call(Mode.prototype);
exports.Mode = Mode;
});

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,326 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var lang = require("ace/lib/lang");
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
var CssHighlightRules = function() {
var properties = lang.arrayToMap(
("-moz-box-sizing|-webkit-box-sizing|appearance|azimuth|background-attachment|background-color|background-image|" +
"background-position|background-repeat|background|border-bottom-color|" +
"border-bottom-style|border-bottom-width|border-bottom|border-collapse|" +
"border-color|border-left-color|border-left-style|border-left-width|" +
"border-left|border-right-color|border-right-style|border-right-width|" +
"border-right|border-spacing|border-style|border-top-color|" +
"border-top-style|border-top-width|border-top|border-width|border|" +
"bottom|box-sizing|caption-side|clear|clip|color|content|counter-increment|" +
"counter-reset|cue-after|cue-before|cue|cursor|direction|display|" +
"elevation|empty-cells|float|font-family|font-size-adjust|font-size|" +
"font-stretch|font-style|font-variant|font-weight|font|height|left|" +
"letter-spacing|line-height|list-style-image|list-style-position|" +
"list-style-type|list-style|margin-bottom|margin-left|margin-right|" +
"margin-top|marker-offset|margin|marks|max-height|max-width|min-height|" +
"min-width|-moz-border-radius|opacity|orphans|outline-color|" +
"outline-style|outline-width|outline|overflow|overflow-x|overflow-y|padding-bottom|" +
"padding-left|padding-right|padding-top|padding|page-break-after|" +
"page-break-before|page-break-inside|page|pause-after|pause-before|" +
"pause|pitch-range|pitch|play-during|position|quotes|richness|right|" +
"size|speak-header|speak-numeral|speak-punctuation|speech-rate|speak|" +
"stress|table-layout|text-align|text-decoration|text-indent|" +
"text-shadow|text-transform|top|unicode-bidi|vertical-align|" +
"visibility|voice-family|volume|white-space|widows|width|word-spacing|" +
"z-index").split("|")
);
var functions = lang.arrayToMap(
("rgb|rgba|url|attr|counter|counters").split("|")
);
var constants = lang.arrayToMap(
("absolute|all-scroll|always|armenian|auto|baseline|below|bidi-override|" +
"block|bold|bolder|border-box|both|bottom|break-all|break-word|capitalize|center|" +
"char|circle|cjk-ideographic|col-resize|collapse|content-box|crosshair|dashed|" +
"decimal-leading-zero|decimal|default|disabled|disc|" +
"distribute-all-lines|distribute-letter|distribute-space|" +
"distribute|dotted|double|e-resize|ellipsis|fixed|georgian|groove|" +
"hand|hebrew|help|hidden|hiragana-iroha|hiragana|horizontal|" +
"ideograph-alpha|ideograph-numeric|ideograph-parenthesis|" +
"ideograph-space|inactive|inherit|inline-block|inline|inset|inside|" +
"inter-ideograph|inter-word|italic|justify|katakana-iroha|katakana|" +
"keep-all|left|lighter|line-edge|line-through|line|list-item|loose|" +
"lower-alpha|lower-greek|lower-latin|lower-roman|lowercase|lr-tb|ltr|" +
"medium|middle|move|n-resize|ne-resize|newspaper|no-drop|no-repeat|" +
"nw-resize|none|normal|not-allowed|nowrap|oblique|outset|outside|" +
"overline|pointer|progress|relative|repeat-x|repeat-y|repeat|right|" +
"ridge|row-resize|rtl|s-resize|scroll|se-resize|separate|small-caps|" +
"solid|square|static|strict|super|sw-resize|table-footer-group|" +
"table-header-group|tb-rl|text-bottom|text-top|text|thick|thin|top|" +
"transparent|underline|upper-alpha|upper-latin|upper-roman|uppercase|" +
"vertical-ideographic|vertical-text|visible|w-resize|wait|whitespace|" +
"zero").split("|")
);
var colors = lang.arrayToMap(
("aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|" +
"purple|red|silver|teal|white|yellow").split("|")
);
// regexp must not have capturing parentheses. Use (?:) instead.
// regexps are ordered -> the first match is used
var numRe = "\\-?(?:(?:[0-9]+)|(?:[0-9]*\\.[0-9]+))";
function ic(str) {
var re = [];
var chars = str.split("");
for (var i=0; i<chars.length; i++) {
re.push(
"[",
chars[i].toLowerCase(),
chars[i].toUpperCase(),
"]"
);
}
return re.join("");
}
var base_ruleset = [
{
token : "comment", // multi line comment
merge : true,
regex : "\\/\\*",
next : "ruleset_comment"
},{
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, {
token : "string", // single line
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, {
token : "constant.numeric",
regex : numRe + ic("em")
}, {
token : "constant.numeric",
regex : numRe + ic("ex")
}, {
token : "constant.numeric",
regex : numRe + ic("px")
}, {
token : "constant.numeric",
regex : numRe + ic("cm")
}, {
token : "constant.numeric",
regex : numRe + ic("mm")
}, {
token : "constant.numeric",
regex : numRe + ic("in")
}, {
token : "constant.numeric",
regex : numRe + ic("pt")
}, {
token : "constant.numeric",
regex : numRe + ic("pc")
}, {
token : "constant.numeric",
regex : numRe + ic("deg")
}, {
token : "constant.numeric",
regex : numRe + ic("rad")
}, {
token : "constant.numeric",
regex : numRe + ic("grad")
}, {
token : "constant.numeric",
regex : numRe + ic("ms")
}, {
token : "constant.numeric",
regex : numRe + ic("s")
}, {
token : "constant.numeric",
regex : numRe + ic("hz")
}, {
token : "constant.numeric",
regex : numRe + ic("khz")
}, {
token : "constant.numeric",
regex : numRe + "%"
}, {
token : "constant.numeric",
regex : numRe
}, {
token : "constant.numeric", // hex6 color
regex : "#[a-fA-F0-9]{6}"
}, {
token : "constant.numeric", // hex3 color
regex : "#[a-fA-F0-9]{3}"
}, {
token : function(value) {
if (properties.hasOwnProperty(value.toLowerCase())) {
return "support.type";
}
else if (functions.hasOwnProperty(value.toLowerCase())) {
return "support.function";
}
else if (constants.hasOwnProperty(value.toLowerCase())) {
return "support.constant";
}
else if (colors.hasOwnProperty(value.toLowerCase())) {
return "support.constant.color";
}
else {
return "text";
}
},
regex : "\\-?[a-zA-Z_][a-zA-Z0-9_\\-]*"
}
];
var ruleset = lang.copyArray(base_ruleset);
ruleset.unshift({
token : "rparen",
regex : "\\}",
next: "start"
});
var media_ruleset = lang.copyArray( base_ruleset );
media_ruleset.unshift({
token : "rparen",
regex : "\\}",
next: "media"
});
var base_comment = [{
token : "comment", // comment spanning whole line
merge : true,
regex : ".+"
}];
var comment = lang.copyArray(base_comment);
comment.unshift({
token : "comment", // closing comment
regex : ".*?\\*\\/",
next : "start"
});
var media_comment = lang.copyArray(base_comment);
media_comment.unshift({
token : "comment", // closing comment
regex : ".*?\\*\\/",
next : "media"
});
var ruleset_comment = lang.copyArray(base_comment);
ruleset_comment.unshift({
token : "comment", // closing comment
regex : ".*?\\*\\/",
next : "ruleset"
});
this.$rules = {
"start" : [{
token : "comment", // multi line comment
merge : true,
regex : "\\/\\*",
next : "comment"
}, {
token: "lparen",
regex: "\\{",
next: "ruleset"
}, {
token: "string",
regex: "@media.*?{",
next: "media"
},{
token: "keyword",
regex: "#[a-zA-Z0-9-_]+"
},{
token: "variable",
regex: "\\.[a-zA-Z0-9-_]+"
},{
token: "string",
regex: ":[a-zA-Z0-9-_]+"
},{
token: "constant",
regex: "[a-zA-Z0-9-_]+"
}],
"media" : [ {
token : "comment", // multi line comment
merge : true,
regex : "\\/\\*",
next : "media_comment"
}, {
token: "lparen",
regex: "\\{",
next: "media_ruleset"
},{
token: "string",
regex: "\\}",
next: "start"
},{
token: "keyword",
regex: "#[a-zA-Z0-9-_]+"
},{
token: "variable",
regex: "\\.[a-zA-Z0-9-_]+"
},{
token: "string",
regex: ":[a-zA-Z0-9-_]+"
},{
token: "constant",
regex: "[a-zA-Z0-9-_]+"
}],
"comment" : comment,
"ruleset" : ruleset,
"ruleset_comment" : ruleset_comment,
"media_ruleset" : media_ruleset,
"media_comment" : media_comment
};
};
oop.inherits(CssHighlightRules, TextHighlightRules);
exports.CssHighlightRules = CssHighlightRules;
});

84
ace/mode/css_test.js Normal file
View file

@ -0,0 +1,84 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
if (typeof process !== "undefined") {
require("../../support/paths");
}
define(function(require, exports, module) {
var Buffer = require("ace/model/buffer").Buffer;
var CssMode = require("ace/mode/css").Mode;
var assert = require("ace/test/assertions");
module.exports = {
name: "CSS",
setUp : function() {
this.mode = new CssMode();
},
"test: toggle comment lines should not do anything" : function() {
var session = new Buffer([" abc", "cde", "fg"].join("\n"));
var comment = this.mode.toggleCommentLines("start", session, 0, 1);
assert.equal([" abc", "cde", "fg"].join("\n"), session.toString());
},
"test: lines should keep indentation" : function() {
assert.equal(" ", this.mode.getNextLineIndent("start", " abc", " "));
assert.equal("\t", this.mode.getNextLineIndent("start", "\tabc", " "));
},
"test: new line after { should increase indent" : function() {
assert.equal(" ", this.mode.getNextLineIndent("start", " abc{", " "));
assert.equal("\t ", this.mode.getNextLineIndent("start", "\tabc { ", " "));
},
"test: no indent increase after { in a comment" : function() {
assert.equal(" ", this.mode.getNextLineIndent("start", " /*{", " "));
assert.equal(" ", this.mode.getNextLineIndent("start", " /*{ ", " "));
}
};
});
if (typeof module !== "undefined" && module === require.main) {
require("asyncjs").test.testcase(module.exports).exec()
}

View file

@ -0,0 +1,98 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
if (typeof process !== "undefined") {
require("../../support/paths");
}
define(function(require, exports, module) {
var CssMode = require("ace/mode/css").Mode;
var assert = require("ace/test/assertions");
module.exports = {
name: "CSS Tokenizer",
setUp : function() {
this.tokenizer = new CssMode().getTokenizer();
},
"test: tokenize pixel number" : function() {
var line = "-12px";
var tokens = this.tokenizer.getLineTokens(line, "ruleset").tokens;
assert.equal(1, tokens.length);
assert.equal("constant.numeric", tokens[0].type);
},
"test: tokenize hex3 color" : function() {
var tokens = this.tokenizer.getLineTokens("#abc", "ruleset").tokens;
assert.equal(1, tokens.length);
assert.equal("constant.numeric", tokens[0].type);
},
"test: tokenize hex6 color" : function() {
var tokens = this.tokenizer.getLineTokens("#abc012", "ruleset").tokens;
assert.equal(1, tokens.length);
assert.equal("constant.numeric", tokens[0].type);
},
"test: tokenize parens" : function() {
var tokens = this.tokenizer.getLineTokens("{()}", "start").tokens;
assert.equal(3, tokens.length);
assert.equal("lparen", tokens[0].type);
assert.equal("text", tokens[1].type);
assert.equal("rparen", tokens[2].type);
},
"test for last rule in ruleset to catch capturing group bugs" : function() {
var tokens = this.tokenizer.getLineTokens("top", "ruleset").tokens;
assert.equal(1, tokens.length);
assert.equal("support.type", tokens[0].type);
}
};
});
if (typeof module !== "undefined" && module === require.main) {
require("asyncjs").test.testcase(module.exports).exec()
}

65
ace/mode/css_worker.js Normal file
View file

@ -0,0 +1,65 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var Mirror = require("ace/worker/mirror").Mirror;
var CSSLint = require("ace/mode/css/csslint").CSSLint;
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();
result = CSSLint.verify(value);
this.sender.emit("csslint", result.messages.map(function(msg) {
delete msg.rule;
return msg;
}));
};
}).call(Worker.prototype);
});

View file

@ -0,0 +1,74 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
if (typeof process !== "undefined") {
require("../../support/paths");
}
define(function(require, exports, module) {
var assert = require("ace/test/assertions");
var Worker = require("ace/mode/css_worker").Worker;
module.exports = {
setUp : function() {
this.sender = {
on: function() {},
callback: function(data, id) {
this.data = data;
},
events: [],
emit: function(type, e) {
this.events.push([type, e]);
}
};
},
"test check for syntax error": function() {
var worker = new Worker(this.sender);
worker.setValue("Juhu Kinners");
worker.deferredUpdate.call();
assert.equal(this.sender.events[0][1][0].type, "error");
}
};
});
if (typeof module !== "undefined" && module === require.main) {
require("asyncjs").test.testcase(module.exports).exec();
}

View file

@ -0,0 +1,95 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
var DocCommentHighlightRules = function() {
this.$rules = {
"start" : [ {
token : "comment.doc.tag",
regex : "@[\\w\\d_]+" // TODO: fix email addresses
}, {
token : "comment.doc",
merge : true,
regex : "\\s+"
}, {
token : "comment.doc",
merge : true,
regex : "TODO"
}, {
token : "comment.doc",
merge : true,
regex : "[^@\\*]+"
}, {
token : "comment.doc",
merge : true,
regex : "."
}]
};
};
oop.inherits(DocCommentHighlightRules, TextHighlightRules);
(function() {
this.getStartRule = function(start) {
return {
token : "comment.doc", // doc comment
merge : true,
regex : "\\/\\*(?=\\*)",
next : start
};
};
this.getEndRule = function (start) {
return {
token : "comment.doc", // closing comment
merge : true,
regex : "\\*\\/",
next : start
};
};
}).call(DocCommentHighlightRules.prototype);
exports.DocCommentHighlightRules = DocCommentHighlightRules;
});

26
ace/mode/groovy.js Normal file
View file

@ -0,0 +1,26 @@
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var JavaScriptMode = require("ace/mode/javascript").Mode;
var Tokenizer = require("ace/tokenizer").Tokenizer;
var GroovyHighlightRules = require("ace/mode/groovy_highlight_rules").GroovyHighlightRules;
var MatchingBraceOutdent = require("ace/mode/matching_brace_outdent").MatchingBraceOutdent;
var CstyleBehaviour = require("ace/mode/behaviour/cstyle").CstyleBehaviour;
var Mode = function() {
this.$tokenizer = new Tokenizer(new GroovyHighlightRules().getRules());
this.$outdent = new MatchingBraceOutdent();
this.$behaviour = new CstyleBehaviour();
};
oop.inherits(Mode, JavaScriptMode);
(function() {
this.createWorker = function(session) {
return null;
};
}).call(Mode.prototype);
exports.Mode = Mode;
});

View file

@ -1,31 +1,31 @@
define(function(require, exports, module) { define(function(require, exports, module) {
"use strict";
var oop = require("../lib/oop"); var oop = require("ace/lib/oop");
var DocCommentHighlightRules = require("./doc_comment_highlight_rules").DocCommentHighlightRules; var lang = require("ace/lib/lang");
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var DocCommentHighlightRules = require("ace/mode/doc_comment_highlight_rules").DocCommentHighlightRules;
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
var GroovyHighlightRules = function() { var GroovyHighlightRules = function() {
var keywords = ( var keywords = lang.arrayToMap(
"assert|with|abstract|continue|for|new|switch|" + ("assert|with|abstract|continue|for|new|switch|" +
"assert|default|goto|package|synchronized|" + "assert|default|goto|package|synchronized|" +
"boolean|do|if|private|this|" + "boolean|do|if|private|this|" +
"break|double|implements|protected|throw|" + "break|double|implements|protected|throw|" +
"byte|else|import|public|throws|" + "byte|else|import|public|throws|" +
"case|enum|instanceof|return|transient|" + "case|enum|instanceof|return|transient|" +
"catch|extends|int|short|try|" + "catch|extends|int|short|try|" +
"char|final|interface|static|void|" + "char|final|interface|static|void|" +
"class|finally|long|strictfp|volatile|" + "class|finally|long|strictfp|volatile|" +
"def|float|native|super|while" "def|float|native|super|while").split("|")
); );
var buildinConstants = ( var buildinConstants = lang.arrayToMap(
"null|Infinity|NaN|undefined" ("null|Infinity|NaN|undefined").split("|")
); );
var langClasses = ( var langClasses = lang.arrayToMap(
"AbstractMethodError|AssertionError|ClassCircularityError|"+ ("AbstractMethodError|AssertionError|ClassCircularityError|"+
"ClassFormatError|Deprecated|EnumConstantNotPresentException|"+ "ClassFormatError|Deprecated|EnumConstantNotPresentException|"+
"ExceptionInInitializerError|IllegalAccessError|"+ "ExceptionInInitializerError|IllegalAccessError|"+
"IllegalThreadStateException|InstantiationError|InternalError|"+ "IllegalThreadStateException|InstantiationError|InternalError|"+
@ -48,18 +48,12 @@ var GroovyHighlightRules = function() {
"ArrayStoreException|ClassCastException|LinkageError|"+ "ArrayStoreException|ClassCastException|LinkageError|"+
"NoClassDefFoundError|ClassNotFoundException|RuntimeException|"+ "NoClassDefFoundError|ClassNotFoundException|RuntimeException|"+
"Exception|ThreadDeath|Error|Throwable|System|ClassLoader|"+ "Exception|ThreadDeath|Error|Throwable|System|ClassLoader|"+
"Cloneable|Class|CharSequence|Comparable|String|Object" "Cloneable|Class|CharSequence|Comparable|String|Object").split("|")
);
var importClasses = lang.arrayToMap(
("").split("|")
); );
// TODO var importClasses = "";
var keywordMapper = this.createKeywordMapper({
"variable.language": "this",
"keyword": keywords,
"support.function": langClasses,
"constant.language": buildinConstants
}, "identifier");
// regexp must not have capturing parentheses. Use (?:) instead. // regexp must not have capturing parentheses. Use (?:) instead.
// regexps are ordered -> the first match is used // regexps are ordered -> the first match is used
@ -69,22 +63,15 @@ var GroovyHighlightRules = function() {
token : "comment", token : "comment",
regex : "\\/\\/.*$" regex : "\\/\\/.*$"
}, },
DocCommentHighlightRules.getStartRule("doc-start"), new DocCommentHighlightRules().getStartRule("doc-start"),
{ {
token : "comment", // multi line comment token : "comment", // multi line comment
merge : true,
regex : "\\/\\*", regex : "\\/\\*",
next : "comment" next : "comment"
}, { }, {
token : "string.regexp", token : "string.regexp",
regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)" regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)"
}, {
token : "string",
regex : '"""',
next : "qqstring"
}, {
token : "string",
regex : "'''",
next : "qstring"
}, { }, {
token : "string", // single line token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]' regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
@ -101,7 +88,20 @@ var GroovyHighlightRules = function() {
token : "constant.language.boolean", token : "constant.language.boolean",
regex : "(?:true|false)\\b" regex : "(?:true|false)\\b"
}, { }, {
token : keywordMapper, token : function(value) {
if (value == "this")
return "variable.language";
else if (keywords.hasOwnProperty(value))
return "keyword";
else if (langClasses.hasOwnProperty(value))
return "support.function";
else if (importClasses.hasOwnProperty(value))
return "support.function";
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
else
return "identifier";
},
// TODO: Unicode escape sequences // TODO: Unicode escape sequences
// TODO: Unicode identifiers // TODO: Unicode identifiers
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
@ -126,45 +126,14 @@ var GroovyHighlightRules = function() {
next : "start" next : "start"
}, { }, {
token : "comment", // comment spanning whole line token : "comment", // comment spanning whole line
merge : true,
regex : ".+" regex : ".+"
} }
],
"qqstring" : [
{
token : "constant.language.escape",
regex : /\\(?:u[0-9A-Fa-f]{4}|.|$)/
}, {
token : "constant.language.escape",
regex : /\$[\w\d]+/
}, {
token : "constant.language.escape",
regex : /\$\{[^"\}]+\}?/
}, {
token : "string",
regex : '"{3,5}',
next : "start"
}, {
token : "string",
regex : '.+?'
}
],
"qstring" : [
{
token : "constant.language.escape",
regex : /\\(?:u[0-9A-Fa-f]{4}|.|$)/
}, {
token : "string",
regex : "'{3,5}",
next : "start"
}, {
token : "string",
regex : ".+?"
}
] ]
}; };
this.embedRules(DocCommentHighlightRules, "doc-", this.embedRules(DocCommentHighlightRules, "doc-",
[ DocCommentHighlightRules.getEndRule("start") ]); [ new DocCommentHighlightRules().getEndRule("start") ]);
}; };
oop.inherits(GroovyHighlightRules, TextHighlightRules); oop.inherits(GroovyHighlightRules, TextHighlightRules);

78
ace/mode/html.js Normal file
View file

@ -0,0 +1,78 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var TextMode = require("ace/mode/text").Mode;
var JavaScriptMode = require("ace/mode/javascript").Mode;
var CssMode = require("ace/mode/css").Mode;
var Tokenizer = require("ace/tokenizer").Tokenizer;
var HtmlHighlightRules = require("ace/mode/html_highlight_rules").HtmlHighlightRules;
var XmlBehaviour = require("ace/mode/behaviour/xml").XmlBehaviour;
var Mode = function() {
var highlighter = new HtmlHighlightRules();
this.$tokenizer = new Tokenizer(highlighter.getRules());
this.$behaviour = new XmlBehaviour();
this.$embeds = highlighter.getEmbeds();
this.createModeDelegates({
"js-": JavaScriptMode,
"css-": CssMode
});
};
oop.inherits(Mode, TextMode);
(function() {
this.toggleCommentLines = function(state, doc, startRow, endRow) {
return 0;
};
this.getNextLineIndent = function(state, line, tab) {
return this.$getIndent(line);
};
this.checkOutdent = function(state, line, input) {
return false;
};
}).call(Mode.prototype);
exports.Mode = Mode;
});

View file

@ -0,0 +1,198 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var CssHighlightRules = require("ace/mode/css_highlight_rules").CssHighlightRules;
var JavaScriptHighlightRules = require("ace/mode/javascript_highlight_rules").JavaScriptHighlightRules;
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
var HtmlHighlightRules = function() {
// regexp must not have capturing parentheses
// regexps are ordered -> the first match is used
function string(state) {
return [{
token : "string",
regex : '".*?"'
}, {
token : "string", // multi line string start
merge : true,
regex : '["].*$',
next : state + "-qqstring"
}, {
token : "string",
regex : "'.*?'"
}, {
token : "string", // multi line string start
merge : true,
regex : "['].*$",
next : state + "-qstring"
}]
}
function multiLineString(quote, state) {
return [{
token : "string",
merge : true,
regex : ".*" + quote,
next : state
}, {
token : "string",
merge : true,
regex : '.+'
}]
}
function tag(states, name, nextState) {
states[name] = [{
token : "text",
regex : "\\s+"
}, {
token : "meta.tag",
regex : "[-_a-zA-Z0-9:]+",
next : name + "-attribute-list"
}, {
token: "empty",
regex: "",
next : name + "-attribute-list"
}];
states[name + "-qstring"] = multiLineString("'", name);
states[name + "-qqstring"] = multiLineString("\"", name);
states[name + "-attribute-list"] = [{
token : "text",
regex : ">",
next : nextState
}, {
token : "entity.other.attribute-name",
regex : "[-_a-zA-Z0-9:]+"
}, {
token : "constant.numeric", // float
regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
}, {
token : "text",
regex : "\\s+"
}].concat(string(name));
};
this.$rules = {
start : [ {
token : "text",
merge : true,
regex : "<\\!\\[CDATA\\[",
next : "cdata"
}, {
token : "xml_pe",
regex : "<\\?.*?\\?>"
}, {
token : "comment",
merge : true,
regex : "<\\!--",
next : "comment"
}, {
token : "text",
regex : "<(?=\s*script)",
next : "script"
}, {
token : "text",
regex : "<(?=\s*style)",
next : "css"
}, {
token : "text", // 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 : ".+"
} ]
};
tag(this.$rules, "tag", "start");
tag(this.$rules, "css", "css-start");
tag(this.$rules, "script", "js-start");
this.embedRules(JavaScriptHighlightRules, "js-", [{
token: "comment",
regex: "\\/\\/.*(?=<\\/script>)",
next: "tag"
}, {
token: "text",
regex: "<\\/(?=script)",
next: "tag"
}]);
this.embedRules(CssHighlightRules, "css-", [{
token: "text",
regex: "<\\/(?=style)",
next: "tag"
}]);
};
oop.inherits(HtmlHighlightRules, TextHighlightRules);
exports.HtmlHighlightRules = HtmlHighlightRules;
});

73
ace/mode/html_test.js Normal file
View file

@ -0,0 +1,73 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
if (typeof process !== "undefined") {
require("../../support/paths");
}
define(function(require, exports, module) {
var Buffer = require("ace/model/buffer").Buffer;
var Range = require("ace/range").Range;
var HtmlMode = require("ace/mode/html").Mode;
var assert = require("ace/test/assertions");
module.exports = {
setUp : function() {
this.mode = new HtmlMode();
},
"test: toggle comment lines should not do anything" : function() {
var session = new Buffer([" 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()
}

View file

@ -0,0 +1,92 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
if (typeof process !== "undefined") {
require("../../support/paths");
}
define(function(require, exports, module) {
var HtmlMode = require("ace/mode/html").Mode;
var assert = require("ace/test/assertions");
module.exports = {
setUp : function() {
this.tokenizer = new HtmlMode().getTokenizer();
},
"test: tokenize embedded script" : function() {
var line = "<script a='a'>var</script>'123'";
var tokens = this.tokenizer.getLineTokens(line, "start").tokens;
//assert.equal(10, tokens.length);
assert.equal("text", tokens[0].type);
assert.equal("meta.tag", tokens[1].type);
assert.equal("text", tokens[2].type);
assert.equal("entity.other.attribute-name", tokens[3].type);
assert.equal("text", tokens[4].type);
assert.equal("string", tokens[5].type);
assert.equal("text", tokens[6].type);
assert.equal("keyword", tokens[7].type);
assert.equal("text", tokens[8].type);
assert.equal("meta.tag", tokens[9].type);
assert.equal("text", tokens[10].type);
},
"test: tokenize multiline attribute value with double quotes": function() {
var line1 = this.tokenizer.getLineTokens('<a href="abc', "start");
var t1 = line1.tokens;
var t2 = this.tokenizer.getLineTokens('def">', line1.state).tokens;
assert.equal(t1[t1.length-1].type, "string");
assert.equal(t2[0].type, "string");
},
"test: tokenize multiline attribute value with single quotes": function() {
var line1 = this.tokenizer.getLineTokens("<a href='abc", "start");
var t1 = line1.tokens;
var t2 = this.tokenizer.getLineTokens('def\'>', line1.state).tokens;
assert.equal(t1[t1.length-1].type, "string");
assert.equal(t2[0].type, "string");
}
};
});
if (typeof module !== "undefined" && module === require.main) {
require("asyncjs").test.testcase(module.exports).exec()
}

26
ace/mode/java.js Normal file
View file

@ -0,0 +1,26 @@
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var JavaScriptMode = require("ace/mode/javascript").Mode;
var Tokenizer = require("ace/tokenizer").Tokenizer;
var JavaHighlightRules = require("ace/mode/java_highlight_rules").JavaHighlightRules;
var MatchingBraceOutdent = require("ace/mode/matching_brace_outdent").MatchingBraceOutdent;
var CstyleBehaviour = require("ace/mode/behaviour/cstyle").CstyleBehaviour;
var Mode = function() {
this.$tokenizer = new Tokenizer(new JavaHighlightRules().getRules());
this.$outdent = new MatchingBraceOutdent();
this.$behaviour = new CstyleBehaviour();
};
oop.inherits(Mode, JavaScriptMode);
(function() {
this.createWorker = function(session) {
return null;
};
}).call(Mode.prototype);
exports.Mode = Mode;
});

View file

@ -1,15 +1,15 @@
define(function(require, exports, module) { define(function(require, exports, module) {
"use strict";
var oop = require("../lib/oop"); var oop = require("ace/lib/oop");
var DocCommentHighlightRules = require("./doc_comment_highlight_rules").DocCommentHighlightRules; var lang = require("ace/lib/lang");
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var DocCommentHighlightRules = require("ace/mode/doc_comment_highlight_rules").DocCommentHighlightRules;
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
var JavaHighlightRules = function() { var JavaHighlightRules = function() {
// taken from http://download.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html // taken from http://download.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html
var keywords = ( var keywords = lang.arrayToMap(
"abstract|continue|for|new|switch|" + ("abstract|continue|for|new|switch|" +
"assert|default|goto|package|synchronized|" + "assert|default|goto|package|synchronized|" +
"boolean|do|if|private|this|" + "boolean|do|if|private|this|" +
"break|double|implements|protected|throw|" + "break|double|implements|protected|throw|" +
@ -18,14 +18,15 @@ var JavaHighlightRules = function() {
"catch|extends|int|short|try|" + "catch|extends|int|short|try|" +
"char|final|interface|static|void|" + "char|final|interface|static|void|" +
"class|finally|long|strictfp|volatile|" + "class|finally|long|strictfp|volatile|" +
"const|float|native|super|while" "const|float|native|super|while").split("|")
); );
var buildinConstants = ("null|Infinity|NaN|undefined"); var buildinConstants = lang.arrayToMap(
("null|Infinity|NaN|undefined").split("|")
);
var langClasses = lang.arrayToMap(
var langClasses = ( ("AbstractMethodError|AssertionError|ClassCircularityError|"+
"AbstractMethodError|AssertionError|ClassCircularityError|"+
"ClassFormatError|Deprecated|EnumConstantNotPresentException|"+ "ClassFormatError|Deprecated|EnumConstantNotPresentException|"+
"ExceptionInInitializerError|IllegalAccessError|"+ "ExceptionInInitializerError|IllegalAccessError|"+
"IllegalThreadStateException|InstantiationError|InternalError|"+ "IllegalThreadStateException|InstantiationError|InternalError|"+
@ -48,16 +49,12 @@ var JavaHighlightRules = function() {
"ArrayStoreException|ClassCastException|LinkageError|"+ "ArrayStoreException|ClassCastException|LinkageError|"+
"NoClassDefFoundError|ClassNotFoundException|RuntimeException|"+ "NoClassDefFoundError|ClassNotFoundException|RuntimeException|"+
"Exception|ThreadDeath|Error|Throwable|System|ClassLoader|"+ "Exception|ThreadDeath|Error|Throwable|System|ClassLoader|"+
"Cloneable|Class|CharSequence|Comparable|String|Object" "Cloneable|Class|CharSequence|Comparable|String|Object").split("|")
);
var importClasses = lang.arrayToMap(
("").split("|")
); );
var keywordMapper = this.createKeywordMapper({
"variable.language": "this",
"keyword": keywords,
"constant.language": buildinConstants,
"support.function": langClasses
}, "identifier");
// regexp must not have capturing parentheses. Use (?:) instead. // regexp must not have capturing parentheses. Use (?:) instead.
// regexps are ordered -> the first match is used // regexps are ordered -> the first match is used
@ -67,11 +64,15 @@ var JavaHighlightRules = function() {
token : "comment", token : "comment",
regex : "\\/\\/.*$" regex : "\\/\\/.*$"
}, },
DocCommentHighlightRules.getStartRule("doc-start"), new DocCommentHighlightRules().getStartRule("doc-start"),
{ {
token : "comment", // multi line comment token : "comment", // multi line comment
merge : true,
regex : "\\/\\*", regex : "\\/\\*",
next : "comment" next : "comment"
}, {
token : "string.regexp",
regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)"
}, { }, {
token : "string", // single line token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]' regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
@ -88,7 +89,20 @@ var JavaHighlightRules = function() {
token : "constant.language.boolean", token : "constant.language.boolean",
regex : "(?:true|false)\\b" regex : "(?:true|false)\\b"
}, { }, {
token : keywordMapper, token : function(value) {
if (value == "this")
return "variable.language";
else if (keywords.hasOwnProperty(value))
return "keyword";
else if (langClasses.hasOwnProperty(value))
return "support.function";
else if (importClasses.hasOwnProperty(value))
return "support.function";
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
else
return "identifier";
},
// TODO: Unicode escape sequences // TODO: Unicode escape sequences
// TODO: Unicode identifiers // TODO: Unicode identifiers
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
@ -113,13 +127,14 @@ var JavaHighlightRules = function() {
next : "start" next : "start"
}, { }, {
token : "comment", // comment spanning whole line token : "comment", // comment spanning whole line
merge : true,
regex : ".+" regex : ".+"
} }
] ]
}; };
this.embedRules(DocCommentHighlightRules, "doc-", this.embedRules(DocCommentHighlightRules, "doc-",
[ DocCommentHighlightRules.getEndRule("start") ]); [ new DocCommentHighlightRules().getEndRule("start") ]);
}; };
oop.inherits(JavaHighlightRules, TextHighlightRules); oop.inherits(JavaHighlightRules, TextHighlightRules);

170
ace/mode/javascript.js Normal file
View file

@ -0,0 +1,170 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var TextMode = require("ace/mode/text").Mode;
var Tokenizer = require("ace/tokenizer").Tokenizer;
var JavaScriptHighlightRules = require("ace/mode/javascript_highlight_rules").JavaScriptHighlightRules;
var MatchingBraceOutdent = require("ace/mode/matching_brace_outdent").MatchingBraceOutdent;
var Range = require("ace/range").Range;
var WorkerClient = require("ace/worker/worker_client").WorkerClient;
var CstyleBehaviour = require("ace/mode/behaviour/cstyle").CstyleBehaviour;
var Mode = function() {
this.$tokenizer = new Tokenizer(new JavaScriptHighlightRules().getRules());
this.$outdent = new MatchingBraceOutdent();
this.$behaviour = new CstyleBehaviour();
};
oop.inherits(Mode, TextMode);
(function() {
this.toggleCommentLines = function(state, doc, startRow, endRow) {
var outdent = true;
var outentedRows = [];
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);
};
this.createWorker = function(session) {
var doc = session.getDocument();
var worker = new WorkerClient(["ace"], "worker-javascript.js", "ace/mode/javascript_worker", "JavaScriptWorker");
worker.call("setValue", [doc.getValue()]);
doc.on("change", function(e) {
e.range = {
start: e.data.range.start,
end: e.data.range.end
};
worker.emit("change", e);
});
worker.on("jslint", function(results) {
var errors = [];
for (var i=0; i<results.data.length; i++) {
var error = results.data[i];
if (error)
errors.push({
row: error.line-1,
column: error.character-1,
text: error.reason,
type: "warning",
lint: error
});
}
session.setAnnotations(errors);
});
worker.on("narcissus", function(e) {
session.setAnnotations([e.data]);
});
worker.on("terminate", function() {
session.clearAnnotations();
});
return worker;
};
}).call(Mode.prototype);
exports.Mode = Mode;
});

View file

@ -0,0 +1,679 @@
/* vim: set sw=4 ts=4 et tw=78: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Narcissus JavaScript engine.
*
* The Initial Developer of the Original Code is
* Brendan Eich <brendan@mozilla.org>.
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Tom Austin <taustin@ucsc.edu>
* Brendan Eich <brendan@mozilla.org>
* Shu-Yu Guo <shu@rfrn.org>
* Dave Herman <dherman@mozilla.com>
* Dimitris Vardoulakis <dimvar@ccs.neu.edu>
* Patrick Walton <pcwalton@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
* Narcissus - JS implemented in JS.
*
* Well-known constants and lookup tables. Many consts are generated from the
* tokens table via eval to minimize redundancy, so consumers must be compiled
* separately to take advantage of the simple switch-case constant propagation
* done by SpiderMonkey.
*/
define(function(require, exports, module) {
var narcissus = {
options: {
version: 185,
// Global variables to hide from the interpreter
hiddenHostGlobals: { Narcissus: true },
// Desugar SpiderMonkey language extensions?
desugarExtensions: false
},
hostSupportsEvalConst: (function() {
try {
return eval("(function(s) { eval(s); return x })('const x = true;')");
} catch (e) {
return false;
}
})(),
hostGlobal: this
};
Narcissus = narcissus;
var tokens = [
// End of source.
"END",
// Operators and punctuators. Some pair-wise order matters, e.g. (+, -)
// and (UNARY_PLUS, UNARY_MINUS).
"\n", ";",
",",
"=",
"?", ":", "CONDITIONAL",
"||",
"&&",
"|",
"^",
"&",
"==", "!=", "===", "!==",
"<", "<=", ">=", ">",
"<<", ">>", ">>>",
"+", "-",
"*", "/", "%",
"!", "~", "UNARY_PLUS", "UNARY_MINUS",
"++", "--",
".",
"[", "]",
"{", "}",
"(", ")",
// Nonterminal tree node type codes.
"SCRIPT", "BLOCK", "LABEL", "FOR_IN", "CALL", "NEW_WITH_ARGS", "INDEX",
"ARRAY_INIT", "OBJECT_INIT", "PROPERTY_INIT", "GETTER", "SETTER",
"GROUP", "LIST", "LET_BLOCK", "ARRAY_COMP", "GENERATOR", "COMP_TAIL",
// Terminals.
"IDENTIFIER", "NUMBER", "STRING", "REGEXP",
// Keywords.
"break",
"case", "catch", "const", "continue",
"debugger", "default", "delete", "do",
"else", "export",
"false", "finally", "for", "function",
"if", "import", "in", "instanceof",
"let", "module",
"new", "null",
"return",
"switch",
"this", "throw", "true", "try", "typeof",
"var", "void",
"yield",
"while", "with",
];
var statementStartTokens = [
"break",
"const", "continue",
"debugger", "do",
"for",
"if",
"return",
"switch",
"throw", "try",
"var",
"yield",
"while", "with",
];
// Whitespace characters (see ECMA-262 7.2)
var whitespaceChars = [
// normal whitespace:
"\u0009", "\u000B", "\u000C", "\u0020", "\u00A0", "\uFEFF",
// high-Unicode whitespace:
"\u1680", "\u180E",
"\u2000", "\u2001", "\u2002", "\u2003", "\u2004", "\u2005", "\u2006",
"\u2007", "\u2008", "\u2009", "\u200A",
"\u202F", "\u205F", "\u3000"
];
var whitespace = {};
for (var i = 0; i < whitespaceChars.length; i++) {
whitespace[whitespaceChars[i]] = true;
}
// Operator and punctuator mapping from token to tree node type name.
// NB: because the lexer doesn't backtrack, all token prefixes must themselves
// be valid tokens (e.g. !== is acceptable because its prefixes are the valid
// tokens != and !).
var opTypeNames = {
'\n': "NEWLINE",
';': "SEMICOLON",
',': "COMMA",
'?': "HOOK",
':': "COLON",
'||': "OR",
'&&': "AND",
'|': "BITWISE_OR",
'^': "BITWISE_XOR",
'&': "BITWISE_AND",
'===': "STRICT_EQ",
'==': "EQ",
'=': "ASSIGN",
'!==': "STRICT_NE",
'!=': "NE",
'<<': "LSH",
'<=': "LE",
'<': "LT",
'>>>': "URSH",
'>>': "RSH",
'>=': "GE",
'>': "GT",
'++': "INCREMENT",
'--': "DECREMENT",
'+': "PLUS",
'-': "MINUS",
'*': "MUL",
'/': "DIV",
'%': "MOD",
'!': "NOT",
'~': "BITWISE_NOT",
'.': "DOT",
'[': "LEFT_BRACKET",
']': "RIGHT_BRACKET",
'{': "LEFT_CURLY",
'}': "RIGHT_CURLY",
'(': "LEFT_PAREN",
')': "RIGHT_PAREN"
};
// Hash of keyword identifier to tokens index. NB: we must null __proto__ to
// avoid toString, etc. namespace pollution.
var keywords = {__proto__: null};
// Define const END, etc., based on the token names. Also map name to index.
var tokenIds = {};
// Building up a string to be eval'd in different contexts.
var consts = Narcissus.hostSupportsEvalConst ? "const " : "var ";
for (var i = 0, j = tokens.length; i < j; i++) {
if (i > 0)
consts += ", ";
var t = tokens[i];
var name;
if (/^[a-z]/.test(t)) {
name = t.toUpperCase();
keywords[t] = i;
} else {
name = (/^\W/.test(t) ? opTypeNames[t] : t);
}
consts += name + " = " + i;
tokenIds[name] = i;
tokens[t] = i;
}
consts += ";";
var isStatementStartCode = {__proto__: null};
for (i = 0, j = statementStartTokens.length; i < j; i++)
isStatementStartCode[keywords[statementStartTokens[i]]] = true;
// Map assignment operators to their indexes in the tokens array.
var assignOps = ['|', '^', '&', '<<', '>>', '>>>', '+', '-', '*', '/', '%'];
for (i = 0, j = assignOps.length; i < j; i++) {
t = assignOps[i];
assignOps[t] = tokens[t];
}
function defineGetter(obj, prop, fn, dontDelete, dontEnum) {
Object.defineProperty(obj, prop,
{ get: fn, configurable: !dontDelete, enumerable: !dontEnum });
}
function defineGetterSetter(obj, prop, getter, setter, dontDelete, dontEnum) {
Object.defineProperty(obj, prop, {
get: getter,
set: setter,
configurable: !dontDelete,
enumerable: !dontEnum
});
}
function defineMemoGetter(obj, prop, fn, dontDelete, dontEnum) {
Object.defineProperty(obj, prop, {
get: function() {
var val = fn();
defineProperty(obj, prop, val, dontDelete, true, dontEnum);
return val;
},
configurable: true,
enumerable: !dontEnum
});
}
function defineProperty(obj, prop, val, dontDelete, readOnly, dontEnum) {
Object.defineProperty(obj, prop,
{ value: val, writable: !readOnly, configurable: !dontDelete,
enumerable: !dontEnum });
}
// Returns true if fn is a native function. (Note: SpiderMonkey specific.)
function isNativeCode(fn) {
// Relies on the toString method to identify native code.
return ((typeof fn) === "function") && fn.toString().match(/\[native code\]/);
}
function getPropertyDescriptor(obj, name) {
while (obj) {
if (({}).hasOwnProperty.call(obj, name))
return Object.getOwnPropertyDescriptor(obj, name);
obj = Object.getPrototypeOf(obj);
}
}
function getPropertyNames(obj) {
var table = Object.create(null, {});
while (obj) {
var names = Object.getOwnPropertyNames(obj);
for (var i = 0, n = names.length; i < n; i++)
table[names[i]] = true;
obj = Object.getPrototypeOf(obj);
}
return Object.keys(table);
}
function getOwnProperties(obj) {
var map = {};
for (var name in Object.getOwnPropertyNames(obj))
map[name] = Object.getOwnPropertyDescriptor(obj, name);
return map;
}
function blacklistHandler(target, blacklist) {
var mask = Object.create(null, {});
var redirect = StringMap.create(blacklist).mapObject(function(name) { return mask; });
return mixinHandler(redirect, target);
}
function whitelistHandler(target, whitelist) {
var catchall = Object.create(null, {});
var redirect = StringMap.create(whitelist).mapObject(function(name) { return target; });
return mixinHandler(redirect, catchall);
}
function mirrorHandler(target, writable) {
var handler = makePassthruHandler(target);
var defineProperty = handler.defineProperty;
handler.defineProperty = function(name, desc) {
if (!desc.enumerable)
throw new Error("mirror property must be enumerable");
if (!desc.configurable)
throw new Error("mirror property must be configurable");
if (desc.writable !== writable)
throw new Error("mirror property must " + (writable ? "" : "not ") + "be writable");
defineProperty(name, desc);
};
handler.fix = function() { };
handler.getOwnPropertyDescriptor = handler.getPropertyDescriptor;
handler.getOwnPropertyNames = getPropertyNames.bind(handler, target);
handler.keys = handler.enumerate;
handler["delete"] = function() { return false; };
handler.hasOwn = handler.has;
return handler;
}
/*
* Mixin proxies break the single-inheritance model of prototypes, so
* the handler treats all properties as own-properties:
*
* X
* |
* +------------+------------+
* | O |
* | | |
* | O O O |
* | | | | |
* | O O O O |
* | | | | | |
* | O O O O O |
* | | | | | | |
* +-(*)--(w)--(x)--(y)--(z)-+
*/
function mixinHandler(redirect, catchall) {
function targetFor(name) {
return hasOwn(redirect, name) ? redirect[name] : catchall;
}
function getMuxPropertyDescriptor(name) {
var desc = getPropertyDescriptor(targetFor(name), name);
if (desc)
desc.configurable = true;
return desc;
}
function getMuxPropertyNames() {
var names1 = Object.getOwnPropertyNames(redirect).filter(function(name) {
return name in redirect[name];
});
var names2 = getPropertyNames(catchall).filter(function(name) {
return !hasOwn(redirect, name);
});
return names1.concat(names2);
}
function enumerateMux() {
var result = Object.getOwnPropertyNames(redirect).filter(function(name) {
return name in redirect[name];
});
for (name in catchall) {
if (!hasOwn(redirect, name))
result.push(name);
};
return result;
}
function hasMux(name) {
return name in targetFor(name);
}
return {
getOwnPropertyDescriptor: getMuxPropertyDescriptor,
getPropertyDescriptor: getMuxPropertyDescriptor,
getOwnPropertyNames: getMuxPropertyNames,
defineProperty: function(name, desc) {
Object.defineProperty(targetFor(name), name, desc);
},
"delete": function(name) {
var target = targetFor(name);
return delete target[name];
},
// FIXME: ha ha ha
fix: function() { },
has: hasMux,
hasOwn: hasMux,
get: function(receiver, name) {
var target = targetFor(name);
return target[name];
},
set: function(receiver, name, val) {
var target = targetFor(name);
target[name] = val;
return true;
},
enumerate: enumerateMux,
keys: enumerateMux
};
}
function makePassthruHandler(obj) {
// Handler copied from
// http://wiki.ecmascript.org/doku.php?id=harmony:proxies&s=proxy%20object#examplea_no-op_forwarding_proxy
return {
getOwnPropertyDescriptor: function(name) {
var desc = Object.getOwnPropertyDescriptor(obj, name);
// a trapping proxy's properties must always be configurable
desc.configurable = true;
return desc;
},
getPropertyDescriptor: function(name) {
var desc = getPropertyDescriptor(obj, name);
// a trapping proxy's properties must always be configurable
desc.configurable = true;
return desc;
},
getOwnPropertyNames: function() {
return Object.getOwnPropertyNames(obj);
},
defineProperty: function(name, desc) {
Object.defineProperty(obj, name, desc);
},
"delete": function(name) { return delete obj[name]; },
fix: function() {
if (Object.isFrozen(obj)) {
return getOwnProperties(obj);
}
// As long as obj is not frozen, the proxy won't allow itself to be fixed.
return undefined; // will cause a TypeError to be thrown
},
has: function(name) { return name in obj; },
hasOwn: function(name) { return ({}).hasOwnProperty.call(obj, name); },
get: function(receiver, name) { return obj[name]; },
// bad behavior when set fails in non-strict mode
set: function(receiver, name, val) { obj[name] = val; return true; },
enumerate: function() {
var result = [];
for (name in obj) { result.push(name); };
return result;
},
keys: function() { return Object.keys(obj); }
};
}
var hasOwnProperty = ({}).hasOwnProperty;
function hasOwn(obj, name) {
return hasOwnProperty.call(obj, name);
}
function StringMap(table, size) {
this.table = table || Object.create(null, {});
this.size = size || 0;
}
StringMap.create = function(table) {
var init = Object.create(null, {});
var size = 0;
var names = Object.getOwnPropertyNames(table);
for (var i = 0, n = names.length; i < n; i++) {
var name = names[i];
init[name] = table[name];
size++;
}
return new StringMap(init, size);
};
StringMap.prototype = {
has: function(x) { return hasOwnProperty.call(this.table, x); },
set: function(x, v) {
if (!hasOwnProperty.call(this.table, x))
this.size++;
this.table[x] = v;
},
get: function(x) { return this.table[x]; },
getDef: function(x, thunk) {
if (!hasOwnProperty.call(this.table, x)) {
this.size++;
this.table[x] = thunk();
}
return this.table[x];
},
forEach: function(f) {
var table = this.table;
for (var key in table)
f.call(this, key, table[key]);
},
map: function(f) {
var table1 = this.table;
var table2 = Object.create(null, {});
this.forEach(function(key, val) {
table2[key] = f.call(this, val, key);
});
return new StringMap(table2, this.size);
},
mapObject: function(f) {
var table1 = this.table;
var table2 = Object.create(null, {});
this.forEach(function(key, val) {
table2[key] = f.call(this, val, key);
});
return table2;
},
toObject: function() {
return this.mapObject(function(val) { return val; });
},
choose: function() {
return Object.getOwnPropertyNames(this.table)[0];
},
remove: function(x) {
if (hasOwnProperty.call(this.table, x)) {
this.size--;
delete this.table[x];
}
},
copy: function() {
var table = Object.create(null, {});
for (var key in this.table)
table[key] = this.table[key];
return new StringMap(table, this.size);
},
toString: function() { return "[object StringMap]" }
};
// an object-key table with poor asymptotics (replace with WeakMap when possible)
function ObjectMap(array) {
this.array = array || [];
}
function searchMap(map, key, found, notFound) {
var a = map.array;
for (var i = 0, n = a.length; i < n; i++) {
var pair = a[i];
if (pair.key === key)
return found(pair, i);
}
return notFound();
}
ObjectMap.prototype = {
has: function(x) {
return searchMap(this, x, function() { return true }, function() { return false });
},
set: function(x, v) {
var a = this.array;
searchMap(this, x,
function(pair) { pair.value = v },
function() { a.push({ key: x, value: v }) });
},
get: function(x) {
return searchMap(this, x,
function(pair) { return pair.value },
function() { return null });
},
getDef: function(x, thunk) {
var a = this.array;
return searchMap(this, x,
function(pair) { return pair.value },
function() {
var v = thunk();
a.push({ key: x, value: v });
return v;
});
},
forEach: function(f) {
var a = this.array;
for (var i = 0, n = a.length; i < n; i++) {
var pair = a[i];
f.call(this, pair.key, pair.value);
}
},
choose: function() {
return this.array[0].key;
},
get size() {
return this.array.length;
},
remove: function(x) {
var a = this.array;
searchMap(this, x,
function(pair, i) { a.splice(i, 1) },
function() { });
},
copy: function() {
return new ObjectMap(this.array.map(function(pair) {
return { key: pair.key, value: pair.value }
}));
},
clear: function() {
this.array = [];
},
toString: function() { return "[object ObjectMap]" }
};
// non-destructive stack
function Stack(elts) {
this.elts = elts || null;
}
Stack.prototype = {
push: function(x) {
return new Stack({ top: x, rest: this.elts });
},
top: function() {
if (!this.elts)
throw new Error("empty stack");
return this.elts.top;
},
isEmpty: function() {
return this.top === null;
},
find: function(test) {
for (var elts = this.elts; elts; elts = elts.rest) {
if (test(elts.top))
return elts.top;
}
return null;
},
has: function(x) {
return Boolean(this.find(function(elt) { return elt === x }));
},
forEach: function(f) {
for (var elts = this.elts; elts; elts = elts.rest) {
f(elts.top);
}
}
};
module.exports = {
tokens: tokens,
whitespace: whitespace,
opTypeNames: opTypeNames,
keywords: keywords,
isStatementStartCode: isStatementStartCode,
tokenIds: tokenIds,
consts: consts,
assignOps: assignOps,
defineGetter: defineGetter,
defineGetterSetter: defineGetterSetter,
defineMemoGetter: defineMemoGetter,
defineProperty: defineProperty,
isNativeCode: isNativeCode,
mirrorHandler: mirrorHandler,
mixinHandler: mixinHandler,
whitelistHandler: whitelistHandler,
blacklistHandler: blacklistHandler,
makePassthruHandler: makePassthruHandler,
StringMap: StringMap,
ObjectMap: ObjectMap,
Stack: Stack
};
});

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,549 @@
/* vim: set sw=4 ts=4 et tw=78: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Narcissus JavaScript engine.
*
* The Initial Developer of the Original Code is
* Brendan Eich <brendan@mozilla.org>.
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Tom Austin <taustin@ucsc.edu>
* Brendan Eich <brendan@mozilla.org>
* Shu-Yu Guo <shu@rfrn.org>
* Dave Herman <dherman@mozilla.com>
* Dimitris Vardoulakis <dimvar@ccs.neu.edu>
* Patrick Walton <pcwalton@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
* Narcissus - JS implemented in JS.
*
* Lexical scanner.
*/
define(function(require, exports, module) {
var definitions = require("ace/mode/javascript/jsdefs");
// Set constants in the local scope.
eval(definitions.consts);
// Banned keywords by language version
const blackLists = { 160: {}, 185: {}, harmony: {} };
blackLists[160][LET] = true;
blackLists[160][MODULE] = true;
blackLists[160][YIELD] = true;
blackLists[185][MODULE] = true;
// Build up a trie of operator tokens.
var opTokens = {};
for (var op in definitions.opTypeNames) {
if (op === '\n' || op === '.')
continue;
var node = opTokens;
for (var i = 0; i < op.length; i++) {
var ch = op[i];
if (!(ch in node))
node[ch] = {};
node = node[ch];
node.op = op;
}
}
/*
* Tokenizer :: (source, filename, line number) -> Tokenizer
*/
function Tokenizer(s, f, l) {
this.cursor = 0;
this.source = String(s);
this.tokens = [];
this.tokenIndex = 0;
this.lookahead = 0;
this.scanNewlines = false;
this.unexpectedEOF = false;
this.filename = f || "";
this.lineno = l || 1;
this.blackList = blackLists[Narcissus.options.version];
this.blockComments = null;
}
Tokenizer.prototype = {
get done() {
// We need to set scanOperand to true here because the first thing
// might be a regexp.
return this.peek(true) === END;
},
get token() {
return this.tokens[this.tokenIndex];
},
match: function (tt, scanOperand) {
return this.get(scanOperand) === tt || this.unget();
},
mustMatch: function (tt) {
if (!this.match(tt)) {
throw this.newSyntaxError("Missing " +
definitions.tokens[tt].toLowerCase());
}
return this.token;
},
peek: function (scanOperand) {
var tt, next;
if (this.lookahead) {
next = this.tokens[(this.tokenIndex + this.lookahead) & 3];
tt = (this.scanNewlines && next.lineno !== this.lineno)
? NEWLINE
: next.type;
} else {
tt = this.get(scanOperand);
this.unget();
}
return tt;
},
peekOnSameLine: function (scanOperand) {
this.scanNewlines = true;
var tt = this.peek(scanOperand);
this.scanNewlines = false;
return tt;
},
lastBlockComment: function() {
var length = this.blockComments.length;
return length ? this.blockComments[length - 1] : null;
},
// Eat comments and whitespace.
skip: function () {
var input = this.source;
this.blockComments = [];
for (;;) {
var ch = input[this.cursor++];
var next = input[this.cursor];
// handle \r, \r\n and (always preferable) \n
if (ch === '\r') {
// if the next character is \n, we don't care about this at all
if (next === '\n') continue;
// otherwise, we want to consider this as a newline
ch = '\n';
}
if (ch === '\n' && !this.scanNewlines) {
this.lineno++;
} else if (ch === '/' && next === '*') {
var commentStart = ++this.cursor;
for (;;) {
ch = input[this.cursor++];
if (ch === undefined)
throw this.newSyntaxError("Unterminated comment");
if (ch === '*') {
next = input[this.cursor];
if (next === '/') {
var commentEnd = this.cursor - 1;
this.cursor++;
break;
}
} else if (ch === '\n') {
this.lineno++;
}
}
this.blockComments.push(input.substring(commentStart, commentEnd));
} else if (ch === '/' && next === '/') {
this.cursor++;
for (;;) {
ch = input[this.cursor++];
next = input[this.cursor];
if (ch === undefined)
return;
if (ch === '\r') {
// check for \r\n
if (next !== '\n') ch = '\n';
}
if (ch === '\n') {
if (this.scanNewlines) {
this.cursor--;
} else {
this.lineno++;
}
break;
}
}
} else if (!(ch in definitions.whitespace)) {
this.cursor--;
return;
}
}
},
// Lex the exponential part of a number, if present. Return true iff an
// exponential part was found.
lexExponent: function() {
var input = this.source;
var next = input[this.cursor];
if (next === 'e' || next === 'E') {
this.cursor++;
ch = input[this.cursor++];
if (ch === '+' || ch === '-')
ch = input[this.cursor++];
if (ch < '0' || ch > '9')
throw this.newSyntaxError("Missing exponent");
do {
ch = input[this.cursor++];
} while (ch >= '0' && ch <= '9');
this.cursor--;
return true;
}
return false;
},
lexZeroNumber: function (ch) {
var token = this.token, input = this.source;
token.type = NUMBER;
ch = input[this.cursor++];
if (ch === '.') {
do {
ch = input[this.cursor++];
} while (ch >= '0' && ch <= '9');
this.cursor--;
this.lexExponent();
token.value = parseFloat(token.start, this.cursor);
} else if (ch === 'x' || ch === 'X') {
do {
ch = input[this.cursor++];
} while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') ||
(ch >= 'A' && ch <= 'F'));
this.cursor--;
token.value = parseInt(input.substring(token.start, this.cursor));
} else if (ch >= '0' && ch <= '7') {
do {
ch = input[this.cursor++];
} while (ch >= '0' && ch <= '7');
this.cursor--;
token.value = parseInt(input.substring(token.start, this.cursor));
} else {
this.cursor--;
this.lexExponent(); // 0E1, &c.
token.value = 0;
}
},
lexNumber: function (ch) {
var token = this.token, input = this.source;
token.type = NUMBER;
var floating = false;
do {
ch = input[this.cursor++];
if (ch === '.' && !floating) {
floating = true;
ch = input[this.cursor++];
}
} while (ch >= '0' && ch <= '9');
this.cursor--;
var exponent = this.lexExponent();
floating = floating || exponent;
var str = input.substring(token.start, this.cursor);
token.value = floating ? parseFloat(str) : parseInt(str);
},
lexDot: function (ch) {
var token = this.token, input = this.source;
var next = input[this.cursor];
if (next >= '0' && next <= '9') {
do {
ch = input[this.cursor++];
} while (ch >= '0' && ch <= '9');
this.cursor--;
this.lexExponent();
token.type = NUMBER;
token.value = parseFloat(token.start, this.cursor);
} else {
token.type = DOT;
token.assignOp = null;
token.value = '.';
}
},
lexString: function (ch) {
var token = this.token, input = this.source;
token.type = STRING;
var hasEscapes = false;
var delim = ch;
if (input.length <= this.cursor)
throw this.newSyntaxError("Unterminated string literal");
while ((ch = input[this.cursor++]) !== delim) {
if (this.cursor == input.length)
throw this.newSyntaxError("Unterminated string literal");
if (ch === '\\') {
hasEscapes = true;
if (++this.cursor == input.length)
throw this.newSyntaxError("Unterminated string literal");
}
}
token.value = hasEscapes
? eval(input.substring(token.start, this.cursor))
: input.substring(token.start + 1, this.cursor - 1);
},
lexRegExp: function (ch) {
var token = this.token, input = this.source;
token.type = REGEXP;
do {
ch = input[this.cursor++];
if (ch === '\\') {
this.cursor++;
} else if (ch === '[') {
do {
if (ch === undefined)
throw this.newSyntaxError("Unterminated character class");
if (ch === '\\')
this.cursor++;
ch = input[this.cursor++];
} while (ch !== ']');
} else if (ch === undefined) {
throw this.newSyntaxError("Unterminated regex");
}
} while (ch !== '/');
do {
ch = input[this.cursor++];
} while (ch >= 'a' && ch <= 'z');
this.cursor--;
token.value = eval(input.substring(token.start, this.cursor));
},
lexOp: function (ch) {
var token = this.token, input = this.source;
// A bit ugly, but it seems wasteful to write a trie lookup routine
// for only 3 characters...
var node = opTokens[ch];
var next = input[this.cursor];
if (next in node) {
node = node[next];
this.cursor++;
next = input[this.cursor];
if (next in node) {
node = node[next];
this.cursor++;
next = input[this.cursor];
}
}
var op = node.op;
if (definitions.assignOps[op] && input[this.cursor] === '=') {
this.cursor++;
token.type = ASSIGN;
token.assignOp = definitions.tokenIds[definitions.opTypeNames[op]];
op += '=';
} else {
token.type = definitions.tokenIds[definitions.opTypeNames[op]];
token.assignOp = null;
}
token.value = op;
},
// FIXME: Unicode escape sequences
lexIdent: function (ch) {
var token = this.token;
var id = ch;
while ((ch = this.getValidIdentifierChar(false)) !== null) {
id += ch;
}
token.type = definitions.keywords[id] || IDENTIFIER;
if (token.type in this.blackList) {
// banned keyword, this is an identifier
token.type = IDENTIFIER;
}
token.value = id;
},
/*
* Tokenizer.get :: void -> token type
*
* Consume input *only* if there is no lookahead.
* Dispatch to the appropriate lexing function depending on the input.
*/
get: function (scanOperand) {
var token;
while (this.lookahead) {
--this.lookahead;
this.tokenIndex = (this.tokenIndex + 1) & 3;
token = this.tokens[this.tokenIndex];
if (token.type !== NEWLINE || this.scanNewlines)
return token.type;
}
this.skip();
this.tokenIndex = (this.tokenIndex + 1) & 3;
token = this.tokens[this.tokenIndex];
if (!token)
this.tokens[this.tokenIndex] = token = {};
var input = this.source;
if (this.cursor >= input.length)
return token.type = END;
token.start = this.cursor;
token.lineno = this.lineno;
var ich = this.getValidIdentifierChar(true);
var ch = (ich === null) ? input[this.cursor++] : null;
if (ich !== null) {
this.lexIdent(ich);
} else if (scanOperand && ch === '/') {
this.lexRegExp(ch);
} else if (ch in opTokens) {
this.lexOp(ch);
} else if (ch === '.') {
this.lexDot(ch);
} else if (ch >= '1' && ch <= '9') {
this.lexNumber(ch);
} else if (ch === '0') {
this.lexZeroNumber(ch);
} else if (ch === '"' || ch === "'") {
this.lexString(ch);
} else if (this.scanNewlines && (ch === '\n' || ch === '\r')) {
// if this was a \r, look for \r\n
if (ch === '\r' && input[this.cursor] === '\n') this.cursor++;
token.type = NEWLINE;
token.value = '\n';
this.lineno++;
} else {
throw this.newSyntaxError("Illegal token");
}
token.end = this.cursor;
return token.type;
},
/*
* Tokenizer.unget :: void -> undefined
*
* Match depends on unget returning undefined.
*/
unget: function () {
if (++this.lookahead === 4) throw "PANIC: too much lookahead!";
this.tokenIndex = (this.tokenIndex - 1) & 3;
},
newSyntaxError: function (m) {
m = (this.filename ? this.filename + ":" : "") + this.lineno + ": " + m;
var e = new SyntaxError(m, this.filename, this.lineno);
e.source = this.source;
e.cursor = this.lookahead
? this.tokens[(this.tokenIndex + this.lookahead) & 3].start
: this.cursor;
return e;
},
/* Gets a single valid identifier char from the input stream, or null
* if there is none.
* Since JavaScript provides no convenient way to determine if a
* character is in a particular Unicode category, we use
* metacircularity to accomplish this (oh yeaaaah!) */
getValidIdentifierChar: function(first) {
var input = this.source;
if (this.cursor >= input.length) return null;
var ch = input[this.cursor];
// first check for \u escapes
if (ch === '\\' && input[this.cursor+1] === 'u') {
// get the character value
try {
ch = String.fromCharCode(parseInt(
input.substring(this.cursor + 2, this.cursor + 6),
16));
} catch (ex) {
return null;
}
this.cursor += 5;
}
// check directly for ASCII
if (ch <= "\u007F") {
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch === '$' || ch === '_' ||
(!first && (ch >= '0' && ch <= '9'))) {
this.cursor++;
return ch;
}
return null;
}
// create an object to test this in
var x = {};
x["x"+ch] = true;
x[ch] = true;
// then use eval to determine if it's a valid character
var valid = false;
try {
valid = (Function("x", "return (x." + (first?"":"x") + ch + ");")(x) === true);
} catch (ex) {}
if (valid) this.cursor++;
return (valid ? ch : null);
},
};
return { Tokenizer: Tokenizer };
});

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,212 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Mihai Sucan <mihai DOT sucan AT gmail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var lang = require("ace/lib/lang");
var unicode = require("ace/unicode");
var DocCommentHighlightRules = require("ace/mode/doc_comment_highlight_rules").DocCommentHighlightRules;
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
var JavaScriptHighlightRules = function() {
var keywords = lang.arrayToMap(
("break|case|catch|continue|default|delete|do|else|finally|for|function|" +
"if|in|instanceof|new|return|switch|throw|try|typeof|let|var|while|with|" +
"const|yield|import|get|set").split("|")
);
var buildinConstants = lang.arrayToMap(
("null|Infinity|NaN|undefined").split("|")
);
var futureReserved = lang.arrayToMap(
("class|enum|extends|super|export|implements|private|" +
"public|interface|package|protected|static").split("|")
);
// TODO: Unicode escape sequences
var identifierRe = "[" + unicode.packages.L + "\\$_]["
+ unicode.packages.L
+ unicode.packages.Mn + unicode.packages.Mc
+ unicode.packages.Nd
+ unicode.packages.Pc + "\\$_]*\\b";
// regexp must not have capturing parentheses. Use (?:) instead.
// regexps are ordered -> the first match is used
this.$rules = {
"start" : [
{
token : "comment",
regex : "\\/\\/.*$"
},
new 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.language.boolean",
regex : "(?:true|false)\\b"
}, {
token : function(value) {
if (value == "this")
return "variable.language";
else if (keywords.hasOwnProperty(value))
return "keyword";
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
else if (futureReserved.hasOwnProperty(value))
return "invalid.illegal";
else if (value == "debugger")
return "invalid.deprecated";
else
return "identifier";
},
regex : identifierRe
}, {
token : "keyword.operator",
regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)",
next : "regex_allowed"
}, {
token : "lparen",
regex : "[[({]",
next : "regex_allowed"
}, {
token : "rparen",
regex : "[\\])}]"
}, {
token : "keyword.operator",
regex : "\\/=?",
next : "regex_allowed"
}, {
token: "comment",
regex: "^#!.*$"
}, {
token : "text",
regex : "\\s+"
}
],
// regular expressions are only allowed after certain tokens. This
// makes sure we don't mix up regexps with the divison operator
"regex_allowed": [
{
token: "string.regexp",
regex: "\\/(?:(?:\\[(?:\\\\]|[^\\]])+\\])"
+ "|(?:\\\\/|[^\\]/]))*"
+ "[/]\\w*",
next: "start"
}, {
token : "text",
regex : "\\s+"
}, {
// immediately return to the start mode without matching
// anything
token: "empty",
regex: "",
next: "start"
}
],
"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-",
[ new DocCommentHighlightRules().getEndRule("start") ]);
};
oop.inherits(JavaScriptHighlightRules, TextHighlightRules);
exports.JavaScriptHighlightRules = JavaScriptHighlightRules;
});

159
ace/mode/javascript_test.js Normal file
View file

@ -0,0 +1,159 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
if (typeof process !== "undefined") {
require("../../support/paths");
}
define(function(require, exports, module) {
var Buffer = require("ace/model/buffer").Buffer;
var Tokenizer = require("ace/tokenizer").Tokenizer;
var JavaScriptMode = require("ace/mode/javascript").Mode;
var assert = require("ace/test/assertions");
module.exports = {
setUp : function() {
this.mode = new JavaScriptMode();
},
"test: getTokenizer() (smoke test)" : function() {
var tokenizer = this.mode.getTokenizer();
assert.ok(tokenizer instanceof Tokenizer);
var tokens = tokenizer.getLineTokens("'juhu'", "start").tokens;
assert.equal("string", tokens[0].type);
},
"test: toggle comment lines should prepend '//' to each line" : function() {
var session = new Buffer([" abc", "cde", "fg"]);
var comment = this.mode.toggleCommentLines("start", session, 0, 1);
assert.equal(["// abc", "//cde", "fg"].join("\n"), session.toString());
},
"test: toggle comment on commented lines should remove leading '//' chars" : function() {
var session = new Buffer(["// abc", "//cde", "fg"]);
var comment = this.mode.toggleCommentLines("start", session, 0, 1);
assert.equal([" abc", "cde", "fg"].join("\n"), session.toString());
},
"test: toggle comment lines twice should return the original text" : function() {
var session = new Buffer([" abc", "cde", "fg"]);
this.mode.toggleCommentLines("start", session, 0, 2);
this.mode.toggleCommentLines("start", session, 0, 2);
assert.equal([" abc", "cde", "fg"].join("\n"), session.toString());
},
"test: toggle comment on multiple lines with one commented line prepend '//' to each line" : function() {
var session = new Buffer(["// abc", "//cde", "fg"]);
var comment = this.mode.toggleCommentLines("start", session, 0, 2);
assert.equal(["//// abc", "////cde", "//fg"].join("\n"), session.toString());
},
"test: toggle comment on a comment line with leading white space": function() {
var session = new Buffer(["//cde", " //fg"]);
var comment = this.mode.toggleCommentLines("start", session, 0, 1);
assert.equal(["cde", " fg"].join("\n"), session.toString());
},
"test: auto indent after opening brace" : function() {
assert.equal(" ", this.mode.getNextLineIndent("start", "if () {", " "));
},
"test: auto indent after case" : function() {
assert.equal(" ", this.mode.getNextLineIndent("start", "case 'juhu':", " "));
},
"test: no auto indent after opening brace in multi line comment" : function() {
assert.equal("", this.mode.getNextLineIndent("start", "/*if () {", " "));
assert.equal(" ", this.mode.getNextLineIndent("comment", " abcd", " "));
},
"test: no auto indent after opening brace in single line comment" : function() {
assert.equal("", this.mode.getNextLineIndent("start", "//if () {", " "));
assert.equal(" ", this.mode.getNextLineIndent("start", " //if () {", " "));
},
"test: no auto indent should add to existing indent" : function() {
assert.equal(" ", this.mode.getNextLineIndent("start", " if () {", " "));
assert.equal(" ", this.mode.getNextLineIndent("start", " cde", " "));
},
"test: special indent in doc comments" : function() {
assert.equal(" * ", this.mode.getNextLineIndent("doc-start", "/**", " "));
assert.equal(" * ", this.mode.getNextLineIndent("doc-start", " /**", " "));
assert.equal(" * ", this.mode.getNextLineIndent("doc-start", " *", " "));
assert.equal(" * ", this.mode.getNextLineIndent("doc-start", " *", " "));
assert.equal(" ", this.mode.getNextLineIndent("doc-start", " abc", " "));
},
"test: no indent after doc comments" : function() {
assert.equal("", this.mode.getNextLineIndent("doc-start", " */", " "));
},
"test: trigger outdent if line is space and new text starts with closing brace" : function() {
assert.ok(this.mode.checkOutdent("start", " ", " }"));
assert.ok(!this.mode.checkOutdent("start", " a ", " }"));
assert.ok(!this.mode.checkOutdent("start", "", "}"));
assert.ok(!this.mode.checkOutdent("start", " ", "a }"));
assert.ok(!this.mode.checkOutdent("start", " }", "}"));
},
"test: auto outdent should indent the line with the same indent as the line with the matching opening brace" : function() {
var session = new Buffer([" function foo() {", " bla", " }"]);
this.mode.autoOutdent("start", session, 2);
assert.equal(" }", session.getLine(2));
},
"test: no auto outdent if no matching brace is found" : function() {
var session = new Buffer([" function foo()", " bla", " }"]);
this.mode.autoOutdent("start", session, 2);
assert.equal(" }", session.getLine(2));
}
};
});
if (typeof module !== "undefined" && module === require.main) {
require("asyncjs").test.testcase(module.exports).exec()
}

View file

@ -0,0 +1,152 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
if (typeof process !== "undefined") {
require("../../support/paths");
}
define(function(require, exports, module) {
var JavaScriptMode = require("ace/mode/javascript").Mode;
var assert = require("ace/test/assertions");
module.exports = {
name: "JavaScript Tokenizer",
setUp : function() {
this.tokenizer = new JavaScriptMode().getTokenizer();
},
"test: tokenize1" : function() {
var line = "foo = function";
var tokens = this.tokenizer.getLineTokens(line, "start").tokens;
assert.equal(5, tokens.length);
assert.equal("identifier", tokens[0].type);
assert.equal("text", tokens[1].type);
assert.equal("keyword.operator", tokens[2].type);
assert.equal("text", tokens[3].type);
assert.equal("keyword", tokens[4].type);
},
"test: tokenize doc comment" : function() {
var line = "abc /** de */ fg";
var tokens = this.tokenizer.getLineTokens(line, "start").tokens;
assert.equal(5, tokens.length);
assert.equal("identifier", tokens[0].type);
assert.equal("text", tokens[1].type);
assert.equal("comment.doc", tokens[2].type);
assert.equal("text", tokens[3].type);
assert.equal("identifier", tokens[4].type);
},
"test: tokenize doc comment with tag" : function() {
var line = "/** @param {} */";
var tokens = this.tokenizer.getLineTokens(line, "start").tokens;
assert.equal(3, tokens.length);
assert.equal("comment.doc", tokens[0].type);
assert.equal("comment.doc.tag", tokens[1].type);
assert.equal("comment.doc", tokens[2].type);
},
"test: tokenize parens" : function() {
var line = "[{( )}]";
var tokens = this.tokenizer.getLineTokens(line, "start").tokens;
assert.equal(7, tokens.length);
assert.equal("lparen", tokens[0].type);
assert.equal("lparen", tokens[1].type);
assert.equal("lparen", tokens[2].type);
assert.equal("text", tokens[3].type);
assert.equal("rparen", tokens[4].type);
assert.equal("rparen", tokens[5].type);
assert.equal("rparen", tokens[6].type);
},
"test for last rule in ruleset to catch capturing group bugs" : function() {
var tokens = this.tokenizer.getLineTokens("}", "start").tokens;
assert.equal(1, tokens.length);
assert.equal("rparen", tokens[0].type);
},
"test tokenize arithmetic expression which looks like a regexp": function() {
var tokens = this.tokenizer.getLineTokens("a/b/c", "start").tokens;
assert.equal(5, tokens.length);
var tokens = this.tokenizer.getLineTokens("a/=b/c", "start").tokens;
assert.equal(5, tokens.length);
},
"test tokenize reg exps" : function() {
var tokens = this.tokenizer.getLineTokens("a=/b/g", "start").tokens;
assert.equal(3, tokens.length);
assert.equal("string.regexp", tokens[2].type);
var tokens = this.tokenizer.getLineTokens("a+/b/g", "start").tokens;
assert.equal(3, tokens.length);
assert.equal("string.regexp", tokens[2].type);
var tokens = this.tokenizer.getLineTokens("a = 1 + /2 + 1/b", "start").tokens;
assert.equal(9, tokens.length);
assert.equal("string.regexp", tokens[8].type);
var tokens = this.tokenizer.getLineTokens("a=/a/ / /a/", "start").tokens;
assert.equal(7, tokens.length);
assert.equal("string.regexp", tokens[2].type);
assert.equal("string.regexp", tokens[6].type);
},
"test tokenize identifier with umlauts": function() {
var tokens = this.tokenizer.getLineTokens("füße", "start").tokens;
assert.equal(1, tokens.length);
}
};
});
if (typeof module !== "undefined" && module === require.main) {
require("asyncjs").test.testcase(module.exports).exec()
}

View file

@ -0,0 +1,39 @@
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var Mirror = require("ace/worker/mirror").Mirror;
var lint = require("ace/mode/javascript/jshint").JSHINT;
var Parser = require("ace/mode/javascript/jsparse");
var JavaScriptWorker = exports.JavaScriptWorker = function(sender) {
Mirror.call(this, sender);
this.setTimeout(500);
};
oop.inherits(JavaScriptWorker, Mirror);
(function() {
this.onUpdate = function() {
var value = this.doc.getValue();
value = value.replace(/^#!.*\n/, "\n");
try {
Parser.parse(value);
} catch(e) {
this.sender.emit("narcissus", {
row: e.lineno-1,
column: null, // TODO convert e.cursor
text: e.message,
type: "error"
});
return;
}
lint(value, {undef: false, onevar: false, passfail: false});
this.sender.emit("jslint", lint.errors);
}
}).call(JavaScriptWorker.prototype);
});

View file

@ -0,0 +1,81 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
if (typeof process !== "undefined") {
require("../../support/paths");
}
define(function(require, exports, module) {
var assert = require("ace/test/assertions");
var JavaScriptWorker = require("ace/mode/javascript_worker").JavaScriptWorker;
module.exports = {
setUp : function() {
this.sender = {
on: function() {},
callback: function(data, id) {
this.data = data;
},
events: [],
emit: function(type, e) {
this.events.push([type, e]);
}
};
},
"test check for syntax error": function() {
var worker = new JavaScriptWorker(this.sender);
worker.setValue("Juhu Kinners");
worker.deferredUpdate.call();
assert.equal(this.sender.events[0][1].type, "error");
},
"test check for narcissus bug": function() {
var worker = new JavaScriptWorker(this.sender);
worker.setValue("if('");
worker.deferredUpdate.call();
assert.equal(this.sender.events[0][1].type, "error");
}
};
});
if (typeof module !== "undefined" && module === require.main) {
require("asyncjs").test.testcase(module.exports).exec();
}

85
ace/mode/json.js Normal file
View file

@ -0,0 +1,85 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var TextMode = require("ace/mode/text").Mode;
var Tokenizer = require("ace/tokenizer").Tokenizer;
var HighlightRules = require("ace/mode/json_highlight_rules").JsonHighlightRules;
var MatchingBraceOutdent = require("ace/mode/matching_brace_outdent").MatchingBraceOutdent;
var Range = require("ace/range").Range;
var CstyleBehaviour = require("ace/mode/behaviour/cstyle").CstyleBehaviour;
var Mode = function() {
this.$tokenizer = new Tokenizer(new HighlightRules().getRules());
this.$outdent = new MatchingBraceOutdent();
this.$behaviour = new CstyleBehaviour();
};
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;
var endState = tokenizedLine.state;
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);
};
}).call(Mode.prototype);
exports.Mode = Mode;
});

View file

@ -0,0 +1,87 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Mihai Sucan <mihai DOT sucan AT gmail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var lang = require("ace/lib/lang");
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
var JsonHighlightRules = function() {
// regexp must not have capturing parentheses. Use (?:) instead.
// regexps are ordered -> the first match is used
this.$rules = {
"start" : [
{
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 : "invalid.illegal", // single quoted strings are not allowed
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, {
token : "invalid.illegal", // comments are not allowed
regex : "\\/\\/.*$"
}, {
token : "lparen",
regex : "[[({]"
}, {
token : "rparen",
regex : "[\\])}]"
}, {
token : "text",
regex : "\\s+"
}
]
};
};
oop.inherits(JsonHighlightRules, TextHighlightRules);
exports.JsonHighlightRules = JsonHighlightRules;
});

View file

@ -0,0 +1,80 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var Range = require("ace/range").Range;
var MatchingBraceOutdent = function() {};
(function() {
this.checkOutdent = function(line, input) {
if (! /^\s+$/.test(line))
return false;
return /^\s*\}/.test(input);
};
this.autoOutdent = function(doc, row) {
var line = doc.getLine(row);
var match = line.match(/^(\s*\})/);
if (!match) return 0;
var column = match[1].length;
var openBracePos = doc.findMatchingBracket({row: row, column: column});
if (!openBracePos || openBracePos.row == row) return 0;
var indent = this.$getIndent(doc.getLine(openBracePos.row));
doc.replace(new Range(row, 0, row, column-1), indent);
};
this.$getIndent = function(line) {
var match = line.match(/^(\s+)/);
if (match) {
return match[1];
}
return "";
};
}).call(MatchingBraceOutdent.prototype);
exports.MatchingBraceOutdent = MatchingBraceOutdent;
});

View file

@ -0,0 +1,80 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var Range = require("ace/range").Range;
var MatchingParensOutdent = function() {};
(function() {
this.checkOutdent = function(line, input) {
if (! /^\s+$/.test(line))
return false;
return /^\s*\)/.test(input);
};
this.autoOutdent = function(doc, row) {
var line = doc.getLine(row);
var match = line.match(/^(\s*\))/);
if (!match) return 0;
var column = match[1].length;
var openBracePos = doc.findMatchingBracket({row: row, column: column});
if (!openBracePos || openBracePos.row == row) return 0;
var indent = this.$getIndent(doc.getLine(openBracePos.row));
doc.replace(new Range(row, 0, row, column-1), indent);
};
this.$getIndent = function(line) {
var match = line.match(/^(\s+)/);
if (match) {
return match[1];
}
return "";
};
}).call(MatchingParensOutdent.prototype);
exports.MatchingParensOutdent = MatchingParensOutdent;
});

102
ace/mode/ocaml.js Normal file
View file

@ -0,0 +1,102 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Sergi Mansilla <sergi AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var TextMode = require("ace/mode/text").Mode;
var Tokenizer = require("ace/tokenizer").Tokenizer;
var OcamlHighlightRules = require("ace/mode/ocaml_highlight_rules").OcamlHighlightRules;
var MatchingBraceOutdent = require("ace/mode/matching_brace_outdent").MatchingBraceOutdent;
var Range = require("ace/range").Range;
var Mode = function() {
this.$tokenizer = new Tokenizer(new OcamlHighlightRules().getRules());
this.$outdent = new MatchingBraceOutdent();
};
oop.inherits(Mode, TextMode);
var indenter = /(?:[({[=:]|[-=]>|\b(?:else|try|with))\s*$/;
(function() {
this.toggleCommentLines = function(state, doc, startRow, endRow) {
var i, line;
var outdent = true;
var re = /^\s*\(\*(.*)\*\)/;
for (i=startRow; i<= endRow; i++) {
if (!re.test(doc.getLine(i))) {
outdent = false;
break;
}
}
var range = new Range(0, 0, 0, 0);
for (i=startRow; i<= endRow; i++) {
line = doc.getLine(i);
range.start.row = i;
range.end.row = i;
range.end.column = line.length;
doc.replace(range, outdent ? line.match(re)[1] : "(*" + line + "*)");
}
};
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.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;
});

View file

@ -1,52 +1,63 @@
/* ***** BEGIN LICENSE BLOCK ***** /* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
* *
* Copyright (c) 2010, Ajax.org B.V. * The contents of this file are subject to the Mozilla Public License Version
* All rights reserved. * 1.1 (the "License"); you may not use this file except in compliance with
* * the License. You may obtain a copy of the License at
* Redistribution and use in source and binary forms, with or without * http://www.mozilla.org/MPL/
* 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 ***** */ * Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Sergi Mansilla <sergi AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK *****
*
*/
define(function(require, exports, module) { define(function(require, exports, module) {
"use strict";
var oop = require("../lib/oop"); var oop = require("ace/lib/oop");
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var lang = require("ace/lib/lang");
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
var OcamlHighlightRules = function() { var OcamlHighlightRules = function() {
var keywords = ( var keywords = lang.arrayToMap((
"and|as|assert|begin|class|constraint|do|done|downto|else|end|" + "and|as|assert|begin|class|constraint|do|done|downto|else|end|" +
"exception|external|for|fun|function|functor|if|in|include|" + "exception|external|for|fun|function|functor|if|in|include|" +
"inherit|initializer|lazy|let|match|method|module|mutable|new|" + "inherit|initializer|lazy|let|match|method|module|mutable|new|" +
"object|of|open|or|private|rec|sig|struct|then|to|try|type|val|" + "object|of|open|or|private|rec|sig|struct|then|to|try|type|val|" +
"virtual|when|while|with" "virtual|when|while|with").split("|")
); );
var builtinConstants = ("true|false"); var builtinConstants = lang.arrayToMap(
("true|false").split("|")
);
var builtinFunctions = ( var builtinFunctions = lang.arrayToMap((
"abs|abs_big_int|abs_float|abs_num|abstract_tag|accept|access|acos|add|" + "abs|abs_big_int|abs_float|abs_num|abstract_tag|accept|access|acos|add|" +
"add_available_units|add_big_int|add_buffer|add_channel|add_char|" + "add_available_units|add_big_int|add_buffer|add_channel|add_char|" +
"add_initializer|add_int_big_int|add_interfaces|add_num|add_string|" + "add_initializer|add_int_big_int|add_interfaces|add_num|add_string|" +
@ -227,14 +238,7 @@ var OcamlHighlightRules = function() {
"MoreLabels|Mutex|Nativeint|Num|Obj|Oo|Parsing|Pervasives|Printexc|" + "MoreLabels|Mutex|Nativeint|Num|Obj|Oo|Parsing|Pervasives|Printexc|" +
"Printf|Queue|Random|Scanf|Scanning|Set|Sort|Stack|State|StdLabels|Str|" + "Printf|Queue|Random|Scanf|Scanning|Set|Sort|Stack|State|StdLabels|Str|" +
"Stream|String|StringLabels|Sys|Thread|ThreadUnix|Tk|Unix|UnixLabels|Weak" "Stream|String|StringLabels|Sys|Thread|ThreadUnix|Tk|Unix|UnixLabels|Weak"
); ).split("|"));
var keywordMapper = this.createKeywordMapper({
"variable.language": "this",
"keyword": keywords,
"constant.language": builtinConstants,
"support.function": builtinFunctions
}, "identifier");
var decimalInteger = "(?:(?:[1-9]\\d*)|(?:0))"; var decimalInteger = "(?:(?:[1-9]\\d*)|(?:0))";
var octInteger = "(?:0[oO]?[0-7]+)"; var octInteger = "(?:0[oO]?[0-7]+)";
@ -257,6 +261,7 @@ var OcamlHighlightRules = function() {
}, },
{ {
token : "comment", token : "comment",
merge : true,
regex : '\\(\\*.*', regex : '\\(\\*.*',
next : "comment" next : "comment"
}, },
@ -270,6 +275,7 @@ var OcamlHighlightRules = function() {
}, },
{ {
token : "string", // " string token : "string", // " string
merge : true,
regex : '"', regex : '"',
next : "qstring" next : "qstring"
}, },
@ -286,7 +292,16 @@ var OcamlHighlightRules = function() {
regex : integer + "\\b" regex : integer + "\\b"
}, },
{ {
token : keywordMapper, token : function(value) {
if (keywords.hasOwnProperty(value))
return "keyword";
else if (builtinConstants.hasOwnProperty(value))
return "constant.language";
else if (builtinFunctions.hasOwnProperty(value))
return "support.function";
else
return "identifier";
},
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, },
{ {
@ -294,11 +309,11 @@ var OcamlHighlightRules = function() {
regex : "\\+\\.|\\-\\.|\\*\\.|\\/\\.|#|;;|\\+|\\-|\\*|\\*\\*\\/|\\/\\/|%|<<|>>|&|\\||\\^|~|<|>|<=|=>|==|!=|<>|<-|=" regex : "\\+\\.|\\-\\.|\\*\\.|\\/\\.|#|;;|\\+|\\-|\\*|\\*\\*\\/|\\/\\/|%|<<|>>|&|\\||\\^|~|<|>|<=|=>|==|!=|<>|<-|="
}, },
{ {
token : "paren.lparen", token : "lparen",
regex : "[[({]" regex : "[[({]"
}, },
{ {
token : "paren.rparen", token : "rparen",
regex : "[\\])}]" regex : "[\\])}]"
}, },
{ {
@ -314,6 +329,7 @@ var OcamlHighlightRules = function() {
}, },
{ {
token : "comment", // comment spanning whole line token : "comment", // comment spanning whole line
merge : true,
regex : ".+" regex : ".+"
} }
], ],
@ -325,6 +341,7 @@ var OcamlHighlightRules = function() {
next : "start" next : "start"
}, { }, {
token : "string", token : "string",
merge : true,
regex : '.+' regex : '.+'
} }
] ]

116
ace/mode/perl.js Normal file
View file

@ -0,0 +1,116 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Panagiotis Astithas <pastith AT gmail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var TextMode = require("ace/mode/text").Mode;
var Tokenizer = require("ace/tokenizer").Tokenizer;
var PerlHighlightRules = require("ace/mode/perl_highlight_rules").PerlHighlightRules;
var MatchingBraceOutdent = require("ace/mode/matching_brace_outdent").MatchingBraceOutdent;
var Range = require("ace/range").Range;
var Mode = function() {
this.$tokenizer = new Tokenizer(new PerlHighlightRules().getRules());
this.$outdent = new MatchingBraceOutdent();
};
oop.inherits(Mode, TextMode);
(function() {
this.toggleCommentLines = function(state, doc, startRow, endRow) {
var outdent = true;
var outentedRows = [];
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;
}
}
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;
});

View file

@ -1,50 +1,59 @@
/* ***** BEGIN LICENSE BLOCK ***** /* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
* *
* Copyright (c) 2010, Ajax.org B.V. * The contents of this file are subject to the Mozilla Public License Version
* All rights reserved. * 1.1 (the "License"); you may not use this file except in compliance with
* * the License. You may obtain a copy of the License at
* Redistribution and use in source and binary forms, with or without * http://www.mozilla.org/MPL/
* modification, are permitted provided that the following conditions are met: *
* * Redistributions of source code must retain the above copyright * Software distributed under the License is distributed on an "AS IS" basis,
* notice, this list of conditions and the following disclaimer. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* * Redistributions in binary form must reproduce the above copyright * for the specific language governing rights and limitations under the
* notice, this list of conditions and the following disclaimer in the * License.
* documentation and/or other materials provided with the distribution. *
* * Neither the name of Ajax.org B.V. nor the * The Original Code is Ajax.org Code Editor (ACE).
* names of its contributors may be used to endorse or promote products *
* derived from this software without specific prior written permission. * The Initial Developer of the Original Code is
* * Ajax.org B.V.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * Portions created by the Initial Developer are Copyright (C) 2010
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * the Initial Developer. All Rights Reserved.
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY * Contributor(s):
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * Panagiotis Astithas <pastith AT gmail DOT com>
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; *
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * Alternatively, the contents of this file may be used under the terms of
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * either the GNU General Public License Version 2 or later (the "GPL"), or
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
* *
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) { define(function(require, exports, module) {
"use strict";
var oop = require("../lib/oop"); var oop = require("ace/lib/oop");
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var lang = require("ace/lib/lang");
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
var PerlHighlightRules = function() { var PerlHighlightRules = function() {
var keywords = ( var keywords = lang.arrayToMap(
"base|constant|continue|else|elsif|for|foreach|format|goto|if|last|local|my|next|" + ("base|constant|continue|else|elsif|for|foreach|format|goto|if|last|local|my|next|" +
"no|package|parent|redo|require|scalar|sub|unless|until|while|use|vars" "no|package|parent|redo|require|scalar|sub|unless|until|while|use|vars").split("|")
); );
var buildinConstants = ("ARGV|ENV|INC|SIG"); var buildinConstants = lang.arrayToMap(
("ARGV|ENV|INC|SIG").split("|")
);
var builtinFunctions = ( var builtinFunctions = lang.arrayToMap(
"getprotobynumber|getprotobyname|getservbyname|gethostbyaddr|" + ("getprotobynumber|getprotobyname|getservbyname|gethostbyaddr|" +
"gethostbyname|getservbyport|getnetbyaddr|getnetbyname|getsockname|" + "gethostbyname|getservbyport|getnetbyaddr|getnetbyname|getsockname|" +
"getpeername|setpriority|getprotoent|setprotoent|getpriority|" + "getpeername|setpriority|getprotoent|setprotoent|getpriority|" +
"endprotoent|getservent|setservent|endservent|sethostent|socketpair|" + "endprotoent|getservent|setservent|endservent|sethostent|socketpair|" +
@ -65,24 +74,17 @@ var PerlHighlightRules = function() {
"join|open|tell|pipe|exit|glob|warn|each|bind|sort|pack|eval|push|" + "join|open|tell|pipe|exit|glob|warn|each|bind|sort|pack|eval|push|" +
"keys|getc|kill|seek|sqrt|send|wait|rand|tied|read|time|exec|recv|" + "keys|getc|kill|seek|sqrt|send|wait|rand|tied|read|time|exec|recv|" +
"eof|chr|int|ord|exp|pos|pop|sin|log|abs|oct|hex|tie|cos|vec|END|ref|" + "eof|chr|int|ord|exp|pos|pop|sin|log|abs|oct|hex|tie|cos|vec|END|ref|" +
"map|die|uc|lc|do" "map|die|uc|lc|do").split("|")
); );
var keywordMapper = this.createKeywordMapper({
"keyword": keywords,
"constant.language": buildinConstants,
"support.function": builtinFunctions
}, "identifier");
// regexp must not have capturing parentheses. Use (?:) instead. // regexp must not have capturing parentheses. Use (?:) instead.
// regexps are ordered -> the first match is used // regexps are ordered -> the first match is used
this.$rules = { this.$rules = {
"start" : [ "start" : [
{ {
token : "comment.doc", token : "comment",
regex : "^=(?:begin|item)\\b", regex : "#.*$"
next : "block_comment"
}, { }, {
token : "string.regexp", token : "string.regexp",
regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)" regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)"
@ -91,6 +93,7 @@ var PerlHighlightRules = function() {
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]' regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, { }, {
token : "string", // multi line string start token : "string", // multi line string start
merge : true,
regex : '["].*\\\\$', regex : '["].*\\\\$',
next : "qqstring" next : "qqstring"
}, { }, {
@ -98,6 +101,7 @@ var PerlHighlightRules = function() {
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']" regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, { }, {
token : "string", // multi line string start token : "string", // multi line string start
merge : true,
regex : "['].*\\\\$", regex : "['].*\\\\$",
next : "qstring" next : "qstring"
}, { }, {
@ -107,14 +111,20 @@ var PerlHighlightRules = function() {
token : "constant.numeric", // float token : "constant.numeric", // float
regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b" regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
}, { }, {
token : keywordMapper, token : function(value) {
if (keywords.hasOwnProperty(value))
return "keyword";
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
else if (builtinFunctions.hasOwnProperty(value))
return "support.function";
else
return "identifier";
},
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, { }, {
token : "keyword.operator", token : "keyword.operator",
regex : "%#|\\$#|\\.\\.\\.|\\|\\|=|>>=|<<=|<=>|&&=|=>|!~|\\^=|&=|\\|=|\\.=|x=|%=|\\/=|\\*=|\\-=|\\+=|=~|\\*\\*|\\-\\-|\\.\\.|\\|\\||&&|\\+\\+|\\->|!=|==|>=|<=|>>|<<|,|=|\\?\\:|\\^|\\||x|%|\\/|\\*|<|&|\\\\|~|!|>|\\.|\\-|\\+|\\-C|\\-b|\\-S|\\-u|\\-t|\\-p|\\-l|\\-d|\\-f|\\-g|\\-s|\\-z|\\-k|\\-e|\\-O|\\-T|\\-B|\\-M|\\-A|\\-X|\\-W|\\-c|\\-R|\\-o|\\-x|\\-w|\\-r|\\b(?:and|cmp|eq|ge|gt|le|lt|ne|not|or|xor)" regex : "\\.\\.\\.|\\|\\|=|>>=|<<=|<=>|&&=|=>|!~|\\^=|&=|\\|=|\\.=|x=|%=|\\/=|\\*=|\\-=|\\+=|=~|\\*\\*|\\-\\-|\\.\\.|\\|\\||&&|\\+\\+|\\->|!=|==|>=|<=|>>|<<|,|=|\\?\\:|\\^|\\||x|%|\\/|\\*|<|&|\\\\|~|!|>|\\.|\\-|\\+|\\-C|\\-b|\\-S|\\-u|\\-t|\\-p|\\-l|\\-d|\\-f|\\-g|\\-s|\\-z|\\-k|\\-e|\\-O|\\-T|\\-B|\\-M|\\-A|\\-X|\\-W|\\-c|\\-R|\\-o|\\-x|\\-w|\\-r|\\b(?:and|cmp|eq|ge|gt|le|lt|ne|not|or|xor)"
}, {
token : "comment",
regex : "#.*$"
}, { }, {
token : "lparen", token : "lparen",
regex : "[[({]" regex : "[[({]"
@ -133,6 +143,7 @@ var PerlHighlightRules = function() {
next : "start" next : "start"
}, { }, {
token : "string", token : "string",
merge : true,
regex : '.+' regex : '.+'
} }
], ],
@ -143,18 +154,9 @@ var PerlHighlightRules = function() {
next : "start" next : "start"
}, { }, {
token : "string", token : "string",
merge : true,
regex : '.+' regex : '.+'
} }
],
"block_comment": [
{
token: "comment.doc",
regex: "^=cut\\b",
next: "start"
},
{
defaultToken: "comment.doc"
}
] ]
}; };
}; };

118
ace/mode/php.js Normal file
View file

@ -0,0 +1,118 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* André Fiedler <fiedler dot andre a t gmail dot com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var TextMode = require("ace/mode/text").Mode;
var Tokenizer = require("ace/tokenizer").Tokenizer;
var PhpHighlightRules = require("ace/mode/php_highlight_rules").PhpHighlightRules;
var MatchingBraceOutdent = require("ace/mode/matching_brace_outdent").MatchingBraceOutdent;
var Range = require("ace/range").Range;
var CstyleBehaviour = require("ace/mode/behaviour/cstyle").CstyleBehaviour;
var Mode = function() {
this.$tokenizer = new Tokenizer(new PhpHighlightRules().getRules());
this.$outdent = new MatchingBraceOutdent();
this.$behaviour = new CstyleBehaviour();
};
oop.inherits(Mode, TextMode);
(function() {
this.toggleCommentLines = function(state, doc, startRow, endRow) {
var outdent = true;
var outentedRows = [];
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;
}
}
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;
});

View file

@ -1,44 +1,49 @@
/* ***** BEGIN LICENSE BLOCK ***** /* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
* *
* Copyright (c) 2010, Ajax.org B.V. * The contents of this file are subject to the Mozilla Public License Version
* All rights reserved. * 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
* *
* Redistribution and use in source and binary forms, with or without * Software distributed under the License is distributed on an "AS IS" basis,
* modification, are permitted provided that the following conditions are met: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* * Redistributions of source code must retain the above copyright * for the specific language governing rights and limitations under the
* notice, this list of conditions and the following disclaimer. * License.
* * 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 * The Original Code is Ajax.org Code Editor (ACE).
* 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 ***** */ * The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* André Fiedler <fiedler dot andre a t gmail dot com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK *****
*/
define(function(require, exports, module) { define(function(require, exports, module) {
"use strict";
var oop = require("../lib/oop"); var oop = require("ace/lib/oop");
var lang = require("../lib/lang"); var lang = require("ace/lib/lang");
var DocCommentHighlightRules = require("./doc_comment_highlight_rules").DocCommentHighlightRules; var DocCommentHighlightRules = require("ace/mode/doc_comment_highlight_rules").DocCommentHighlightRules;
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
var HtmlHighlightRules = require("./html_highlight_rules").HtmlHighlightRules;
var PhpLangHighlightRules = function() { var PhpHighlightRules = function() {
var docComment = DocCommentHighlightRules;
// http://php.net/quickref.php // http://php.net/quickref.php
var builtinFunctions = lang.arrayToMap( var builtinFunctions = lang.arrayToMap(
('abs|acos|acosh|addcslashes|addslashes|aggregate|aggregate_info|aggregate_methods|aggregate_methods_by_list|aggregate_methods_by_regexp|' + ('abs|acos|acosh|addcslashes|addslashes|aggregate|aggregate_info|aggregate_methods|aggregate_methods_by_list|aggregate_methods_by_regexp|' +
@ -898,24 +903,45 @@ var PhpLangHighlightRules = function() {
this.$rules = { this.$rules = {
"start" : [ "start" : [
{ {
token : "comment", token : "support", // php open tag
regex : /(?:#|\/\/)(?:[^?]|\?[^>])*/ regex : "<\\?(?:php|\\=)"
}, },
docComment.getStartRule("doc-start"), {
token : "support", // php close tag
regex : "\\?>"
},
{
token : "comment",
regex : "\\/\\/.*$"
},
{
token : "comment",
regex : "#.*$"
},
new DocCommentHighlightRules().getStartRule("doc-start"),
{ {
token : "comment", // multi line comment token : "comment", // multi line comment
merge : true,
regex : "\\/\\*", regex : "\\/\\*",
next : "comment" next : "comment"
}, { }, {
token : "string.regexp", token : "string.regexp",
regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/][gimy]*\\s*(?=[).,;]|$)" regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/][gimy]*\\s*(?=[).,;]|$)"
}, { }, {
token : "string", // " string start token : "string", // single line
regex : '"', regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, {
token : "string", // multi line string start
merge : true,
regex : '["].*\\\\$',
next : "qqstring" next : "qqstring"
}, { }, {
token : "string", // ' string start token : "string", // single line
regex : "'", regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, {
token : "string", // multi line string start
merge : true,
regex : "['].*\\\\$",
next : "qstring" next : "qstring"
}, { }, {
token : "constant.numeric", // hex token : "constant.numeric", // hex
@ -930,12 +956,6 @@ var PhpLangHighlightRules = function() {
"HP_(?:BINDIR|CONFIG_FILE_(?:PATH|SCAN_DIR)|DATADIR|E(?:OL|XTENSION_DIR)|INT_(?:MAX|SIZE)|" + "HP_(?:BINDIR|CONFIG_FILE_(?:PATH|SCAN_DIR)|DATADIR|E(?:OL|XTENSION_DIR)|INT_(?:MAX|SIZE)|" +
"L(?:IBDIR|OCALSTATEDIR)|O(?:S|UTPUT_HANDLER_(?:CONT|END|START))|PREFIX|S(?:API|HLIB_SUFFIX|YSCONFDIR)|" + "L(?:IBDIR|OCALSTATEDIR)|O(?:S|UTPUT_HANDLER_(?:CONT|END|START))|PREFIX|S(?:API|HLIB_SUFFIX|YSCONFDIR)|" +
"VERSION))|__COMPILER_HALT_OFFSET__)\\b" "VERSION))|__COMPILER_HALT_OFFSET__)\\b"
}, {
token : ["keyword", "text", "support.class"],
regex : "\\b(new)(\\s+)(\\w+)"
}, {
token : ["support.class", "keyword.operator"],
regex : "\\b(\\w+)(::)"
}, { }, {
token : "constant.language", // constants token : "constant.language", // constants
regex : "\\b(?:A(?:B(?:DAY_(?:1|2|3|4|5|6|7)|MON_(?:1(?:0|1|2|)|2|3|4|5|6|7|8|9))|LT_DIGITS|M_STR|" + regex : "\\b(?:A(?:B(?:DAY_(?:1|2|3|4|5|6|7)|MON_(?:1(?:0|1|2|)|2|3|4|5|6|7|8|9))|LT_DIGITS|M_STR|" +
@ -956,7 +976,11 @@ var PhpLangHighlightRules = function() {
"T(?:HOUS(?:ANDS_SEP|EP)|_FMT(?:_AMPM|))|YES(?:EXPR|STR)|STD(?:IN|OUT|ERR))\\b" "T(?:HOUS(?:ANDS_SEP|EP)|_FMT(?:_AMPM|))|YES(?:EXPR|STR)|STD(?:IN|OUT|ERR))\\b"
}, { }, {
token : function(value) { token : function(value) {
if (keywords.hasOwnProperty(value)) if (keywordsDeprecated.hasOwnProperty(value))
return "invalid.deprecated";
else if (keywords.hasOwnProperty(value))
return "keyword";
else if (languageConstructs.hasOwnProperty(value))
return "keyword"; return "keyword";
else if (builtinConstants.hasOwnProperty(value)) else if (builtinConstants.hasOwnProperty(value))
return "constant.language"; return "constant.language";
@ -964,122 +988,72 @@ var PhpLangHighlightRules = function() {
return "variable.language"; return "variable.language";
else if (futureReserved.hasOwnProperty(value)) else if (futureReserved.hasOwnProperty(value))
return "invalid.illegal"; return "invalid.illegal";
else if (builtinFunctionsDeprecated.hasOwnProperty(value))
return "invalid.deprecated";
else if (builtinFunctions.hasOwnProperty(value)) else if (builtinFunctions.hasOwnProperty(value))
return "support.function"; return "support.function";
else if (value == "debugger")
return "invalid.deprecated";
else else
if(value.match(/^(\$[a-zA-Z_\x7f-\uffff][a-zA-Z0-9_\x7f-\uffff]*|self|parent)$/)) if(value.match(/^(\$[a-zA-Z_][a-zA-Z0-9_]*|self|parent)$/))
return "variable"; return "variable";
return "identifier"; return "identifier";
}, },
regex : /[a-zA-Z_$\x7f-\uffff][a-zA-Z0-9_\x7f-\uffff]*/ // TODO: Unicode escape sequences
}, { // TODO: Unicode identifiers
onMatch : function(value, currentSate, state) { regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
value = value.substr(3);
if (value[0] == "'" || value[0] == '"')
value = value.slice(1, -1);
state.unshift(this.next, value);
return "markup.list";
},
regex : /<<<(?:\w+|'\w+'|"\w+")$/,
next: "heredoc"
}, { }, {
token : "keyword.operator", token : "keyword.operator",
regex : "::|!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|!=|!==|<=|>=|=>|<<=|>>=|>>>=|<>|<|>|=|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)" regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)"
}, { }, {
token : "paren.lparen", token : "lparen",
regex : "[[({]" regex : "[[({]"
}, { }, {
token : "paren.rparen", token : "rparen",
regex : "[\\])}]" regex : "[\\])}]"
}, { }, {
token : "text", token : "text",
regex : "\\s+" regex : "\\s+"
} }
], ],
"heredoc" : [
{
onMatch : function(value, currentSate, stack) {
if (stack[1] != value)
return "string";
stack.shift();
stack.shift();
return "markup.list";
},
regex : "^\\w+(?=;?$)",
next: "start"
}, {
token: "string",
regex : ".*"
}
],
"comment" : [ "comment" : [
{ {
token : "comment", token : "comment", // closing comment
regex : "\\*\\/", regex : ".*?\\*\\/",
next : "start" next : "start"
}, { }, {
defaultToken : "comment" token : "comment", // comment spanning whole line
merge : true,
regex : ".+"
} }
], ],
"qqstring" : [ "qqstring" : [
{ {
token : "constant.language.escape", token : "string",
regex : '\\\\(?:[nrtvef\\\\"$]|[0-7]{1,3}|x[0-9A-Fa-f]{1,2})' regex : '(?:(?:\\\\.)|(?:[^"\\\\]))*?"',
next : "start"
}, { }, {
token : "variable", token : "string",
regex : /\$[\w]+(?:\[[\w\]+]|[=\-]>\w+)?/ merge : true,
}, { regex : '.+'
token : "variable", }
regex : /\$\{[^"\}]+\}?/ // this is wrong but ok for now
},
{token : "string", regex : '"', next : "start"},
{defaultToken : "string"}
], ],
"qstring" : [ "qstring" : [
{token : "constant.language.escape", regex : /\\['\\]/}, {
{token : "string", regex : "'", next : "start"}, token : "string",
{defaultToken : "string"} regex : "(?:(?:\\\\.)|(?:[^'\\\\]))*?'",
next : "start"
}, {
token : "string",
merge : true,
regex : '.+'
}
] ]
}; };
this.embedRules(DocCommentHighlightRules, "doc-", this.embedRules(DocCommentHighlightRules, "doc-",
[ DocCommentHighlightRules.getEndRule("start") ]); [ new DocCommentHighlightRules().getEndRule("start") ]);
}; };
oop.inherits(PhpLangHighlightRules, TextHighlightRules); oop.inherits(PhpHighlightRules, TextHighlightRules);
var PhpHighlightRules = function() {
HtmlHighlightRules.call(this);
var startRules = [
{
token : "support.php_tag", // php open tag
regex : "<\\?(?:php|=)?",
push : "php-start"
}
];
var endRules = [
{
token : "support.php_tag", // php close tag
regex : "\\?>",
next : "pop"
}
];
for (var key in this.$rules)
this.$rules[key].unshift.apply(this.$rules[key], startRules);
this.embedRules(PhpLangHighlightRules, "php-", endRules, ["start"]);
this.normalizeRules();
};
oop.inherits(PhpHighlightRules, HtmlHighlightRules);
exports.PhpHighlightRules = PhpHighlightRules; exports.PhpHighlightRules = PhpHighlightRules;
exports.PhpLangHighlightRules = PhpLangHighlightRules;
}); });

117
ace/mode/python.js Normal file
View file

@ -0,0 +1,117 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Colin Gourlay <colin DOT j DOT gourlay AT gmail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var TextMode = require("ace/mode/text").Mode;
var Tokenizer = require("ace/tokenizer").Tokenizer;
var PythonHighlightRules = require("ace/mode/python_highlight_rules").PythonHighlightRules;
var MatchingBraceOutdent = require("ace/mode/matching_brace_outdent").MatchingBraceOutdent;
var Range = require("ace/range").Range;
var Mode = function() {
this.$tokenizer = new Tokenizer(new PythonHighlightRules().getRules());
this.$outdent = new MatchingBraceOutdent();
};
oop.inherits(Mode, TextMode);
(function() {
this.toggleCommentLines = function(state, doc, startRow, endRow) {
var outdent = true;
var outentedRows = [];
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;
}
}
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;
});

View file

@ -0,0 +1,181 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Colin Gourlay <colin DOT j DOT gourlay AT gmail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK *****
*
* TODO: python delimiters
*/
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var lang = require("ace/lib/lang");
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
var PythonHighlightRules = function() {
var keywords = lang.arrayToMap(
("and|as|assert|break|class|continue|def|del|elif|else|except|exec|" +
"finally|for|from|global|if|import|in|is|lambda|not|or|pass|print|" +
"raise|return|try|while|with|yield").split("|")
);
var builtinConstants = lang.arrayToMap(
("True|False|None|NotImplemented|Ellipsis|__debug__").split("|")
);
var builtinFunctions = lang.arrayToMap(
("abs|divmod|input|open|staticmethod|all|enumerate|int|ord|str|any|" +
"eval|isinstance|pow|sum|basestring|execfile|issubclass|print|super|" +
"binfile|iter|property|tuple|bool|filter|len|range|type|bytearray|" +
"float|list|raw_input|unichr|callable|format|locals|reduce|unicode|" +
"chr|frozenset|long|reload|vars|classmethod|getattr|map|repr|xrange|" +
"cmp|globals|max|reversed|zip|compile|hasattr|memoryview|round|" +
"__import__|complex|hash|min|set|apply|delattr|help|next|setattr|" +
"buffer|dict|hex|object|slice|coerce|dir|id|oct|sorted|intern").split("|")
);
var futureReserved = lang.arrayToMap(
("").split("|")
);
var strPre = "(?:r|u|ur|R|U|UR|Ur|uR)?";
var decimalInteger = "(?:(?:[1-9]\\d*)|(?:0))";
var octInteger = "(?:0[oO]?[0-7]+)";
var hexInteger = "(?:0[xX][\\dA-Fa-f]+)";
var binInteger = "(?:0[bB][01]+)";
var integer = "(?:" + decimalInteger + "|" + octInteger + "|" + hexInteger + "|" + binInteger + ")";
var exponent = "(?:[eE][+-]?\\d+)";
var fraction = "(?:\\.\\d+)";
var intPart = "(?:\\d+)";
var pointFloat = "(?:(?:" + intPart + "?" + fraction + ")|(?:" + intPart + "\\.))";
var exponentFloat = "(?:(?:" + pointFloat + "|" + intPart + ")" + exponent + ")";
var floatNumber = "(?:" + exponentFloat + "|" + pointFloat + ")";
this.$rules = {
"start" : [ {
token : "comment",
regex : "#.*$"
}, {
token : "string", // """ string
regex : strPre + '"{3}(?:[^\\\\]|\\\\.)*?"{3}'
}, {
token : "string", // multi line """ string start
merge : true,
regex : strPre + '"{3}.*$',
next : "qqstring"
}, {
token : "string", // " string
regex : strPre + '"(?:[^\\\\]|\\\\.)*?"'
}, {
token : "string", // ''' string
regex : strPre + "'{3}(?:[^\\\\]|\\\\.)*?'{3}"
}, {
token : "string", // multi line ''' string start
merge : true,
regex : strPre + "'{3}.*$",
next : "qstring"
}, {
token : "string", // ' string
regex : strPre + "'(?:[^\\\\]|\\\\.)*?'"
}, {
token : "constant.numeric", // imaginary
regex : "(?:" + floatNumber + "|\\d+)[jJ]\\b"
}, {
token : "constant.numeric", // float
regex : floatNumber
}, {
token : "constant.numeric", // long integer
regex : integer + "[lL]\\b"
}, {
token : "constant.numeric", // integer
regex : integer + "\\b"
}, {
token : function(value) {
if (keywords.hasOwnProperty(value))
return "keyword";
else if (builtinConstants.hasOwnProperty(value))
return "constant.language";
else if (futureReserved.hasOwnProperty(value))
return "invalid.illegal";
else if (builtinFunctions.hasOwnProperty(value))
return "support.function";
else if (value == "debugger")
return "invalid.deprecated";
else
return "identifier";
},
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, {
token : "keyword.operator",
regex : "\\+|\\-|\\*|\\*\\*|\\/|\\/\\/|%|<<|>>|&|\\||\\^|~|<|>|<=|=>|==|!=|<>|="
}, {
token : "lparen",
regex : "[\\[\\(\\{]"
}, {
token : "rparen",
regex : "[\\]\\)\\}]"
}, {
token : "text",
regex : "\\s+"
} ],
"qqstring" : [ {
token : "string", // multi line """ string end
regex : '(?:[^\\\\]|\\\\.)*?"{3}',
next : "start"
}, {
token : "string",
merge : true,
regex : '.+'
} ],
"qstring" : [ {
token : "string", // multi line ''' string end
regex : "(?:[^\\\\]|\\\\.)*?'{3}",
next : "start"
}, {
token : "string",
merge : true,
regex : '.+'
} ]
};
};
oop.inherits(PythonHighlightRules, TextHighlightRules);
exports.PythonHighlightRules = PythonHighlightRules;
});

117
ace/mode/ruby.js Normal file
View file

@ -0,0 +1,117 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Shlomo Zalman Heigh <shlomozalmanheigh AT gmail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var TextMode = require("ace/mode/text").Mode;
var Tokenizer = require("ace/tokenizer").Tokenizer;
var RubyHighlightRules = require("ace/mode/ruby_highlight_rules").RubyHighlightRules;
var MatchingBraceOutdent = require("ace/mode/matching_brace_outdent").MatchingBraceOutdent;
var Range = require("ace/range").Range;
var Mode = function() {
this.$tokenizer = new Tokenizer(new RubyHighlightRules().getRules());
this.$outdent = new MatchingBraceOutdent();
};
oop.inherits(Mode, TextMode);
(function() {
this.toggleCommentLines = function(state, doc, startRow, endRow) {
var outdent = true;
var outentedRows = [];
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;
}
}
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;
});

View file

@ -0,0 +1,193 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Shlomo Zalman Heigh <shlomozalmanheigh AT gmail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("ace/lib/oop");
var lang = require("ace/lib/lang");
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
var RubyHighlightRules = function() {
var builtinFunctions = lang.arrayToMap(
("abort|Array|assert|assert_equal|assert_not_equal|assert_same|assert_not_same|" +
"assert_nil|assert_not_nil|assert_match|assert_no_match|assert_in_delta|assert_throws|" +
"assert_raise|assert_nothing_raised|assert_instance_of|assert_kind_of|assert_respond_to|" +
"assert_operator|assert_send|assert_difference|assert_no_difference|assert_recognizes|" +
"assert_generates|assert_response|assert_redirected_to|assert_template|assert_select|" +
"assert_select_email|assert_select_rjs|assert_select_encoded|css_select|at_exit|" +
"attr|attr_writer|attr_reader|attr_accessor|attr_accessible|autoload|binding|block_given?|callcc|" +
"caller|catch|chomp|chomp!|chop|chop!|defined?|delete_via_redirect|eval|exec|exit|" +
"exit!|fail|Float|flunk|follow_redirect!|fork|form_for|form_tag|format|gets|global_variables|gsub|" +
"gsub!|get_via_redirect|h|host!|https?|https!|include|Integer|lambda|link_to|" +
"link_to_unless_current|link_to_function|link_to_remote|load|local_variables|loop|open|open_session|" +
"p|print|printf|proc|putc|puts|post_via_redirect|put_via_redirect|raise|rand|" +
"raw|readline|readlines|redirect?|request_via_redirect|require|scan|select|" +
"set_trace_func|sleep|split|sprintf|srand|String|stylesheet_link_tag|syscall|system|sub|sub!|test|" +
"throw|trace_var|trap|untrace_var|atan2|cos|exp|frexp|ldexp|log|log10|sin|sqrt|tan|" +
"render|javascript_include_tag|csrf_meta_tag|label_tag|text_field_tag|submit_tag|check_box_tag|" +
"content_tag|radio_button_tag|text_area_tag|password_field_tag|hidden_field_tag|" +
"fields_for|select_tag|options_for_select|options_from_collection_for_select|collection_select|" +
"time_zone_select|select_date|select_time|select_datetime|date_select|time_select|datetime_select|" +
"select_year|select_month|select_day|select_hour|select_minute|select_second|file_field_tag|" +
"file_field|respond_to|skip_before_filter|around_filter|after_filter|verify|" +
"protect_from_forgery|rescue_from|helper_method|redirect_to|before_filter|" +
"send_data|send_file|validates_presence_of|validates_uniqueness_of|validates_length_of|" +
"validates_format_of|validates_acceptance_of|validates_associated|validates_exclusion_of|" +
"validates_inclusion_of|validates_numericality_of|validates_with|validates_each|" +
"authenticate_or_request_with_http_basic|authenticate_or_request_with_http_digest|" +
"filter_parameter_logging|match|get|post|resources|redirect|scope|assert_routing|" +
"translate|localize|extract_locale_from_tld|t|l|caches_page|expire_page|caches_action|expire_action|" +
"cache|expire_fragment|expire_cache_for|observe|cache_sweeper|" +
"has_many|has_one|belongs_to|has_and_belongs_to_many").split("|")
);
var keywords = lang.arrayToMap(
("alias|and|BEGIN|begin|break|case|class|def|defined|do|else|elsif|END|end|ensure|" +
"__FILE__|finally|for|gem|if|in|__LINE__|module|next|not|or|private|protected|public|" +
"redo|rescue|retry|return|super|then|undef|unless|until|when|while|yield").split("|")
);
var buildinConstants = lang.arrayToMap(
("true|TRUE|false|FALSE|nil|NIL|ARGF|ARGV|DATA|ENV|RUBY_PLATFORM|RUBY_RELEASE_DATE|" +
"RUBY_VERSION|STDERR|STDIN|STDOUT|TOPLEVEL_BINDING").split("|")
);
var builtinVariables = lang.arrayToMap(
("\$DEBUG|\$defout|\$FILENAME|\$LOAD_PATH|\$SAFE|\$stdin|\$stdout|\$stderr|\$VERBOSE|" +
"$!|root_url|flash|session|cookies|params|request|response|logger").split("|")
);
// 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
merge : true,
regex : "^\=begin$",
next : "comment"
}, {
token : "string.regexp",
regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)"
}, {
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, {
token : "string", // single line
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, {
token : "string", // backtick string
regex : "[`](?:(?:\\\\.)|(?:[^'\\\\]))*?[`]"
}, {
token : "text", // namespaces aren't symbols
regex : "::"
}, {
token : "variable.instancce", // instance variable
regex : "@{1,2}(?:[a-zA-Z_]|\d)+"
}, {
token : "variable.class", // class name
regex : "[A-Z](?:[a-zA-Z_]|\d)+"
}, {
token : "string", // symbol
regex : "[:](?:[A-Za-z_]|[@$](?=[a-zA-Z0-9_]))[a-zA-Z0-9_]*[!=?]?"
}, {
token : "constant.numeric", // hex
regex : "0[xX][0-9a-fA-F](?:[0-9a-fA-F]|_(?=[0-9a-fA-F]))*\\b"
}, {
token : "constant.numeric", // float
regex : "[+-]?\\d(?:\\d|_(?=\\d))*(?:(?:\\.\\d(?:\\d|_(?=\\d))*)?(?:[eE][+-]?\\d+)?)?\\b"
}, {
token : "constant.language.boolean",
regex : "(?:true|false)\\b"
}, {
token : function(value) {
if (value == "self")
return "variable.language";
else if (keywords.hasOwnProperty(value))
return "keyword";
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
else if (builtinVariables.hasOwnProperty(value))
return "variable.language";
else if (builtinFunctions.hasOwnProperty(value))
return "support.function";
else if (value == "debugger")
return "invalid.deprecated";
else
return "identifier";
},
// 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 : "lparen",
regex : "[[({]"
}, {
token : "rparen",
regex : "[\\])}]"
}, {
token : "text",
regex : "\\s+"
}
],
"comment" : [
{
token : "comment", // closing comment
regex : "^\=end$",
next : "start"
}, {
token : "comment", // comment spanning whole line
merge : true,
regex : ".+"
}
]
};
};
oop.inherits(RubyHighlightRules, TextHighlightRules);
exports.RubyHighlightRules = RubyHighlightRules;
});

View file

@ -0,0 +1,115 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Trent Ogren <me AT trentogren DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
if (typeof process !== "undefined") {
require("../../support/paths");
}
define(function(require, exports, module) {
var RubyMode = require("ace/mode/ruby").Mode;
var assert = require("ace/test/assertions");
module.exports = {
name: "Ruby Tokenizer",
setUp : function() {
this.tokenizer = new RubyMode().getTokenizer();
},
"test: symbol tokenizer" : function() {
// https://gist.github.com/1072693
assertValidTokens(this.tokenizer, "string",
[":@thing", ":$thing", ":_thing", ":thing", ":Thing", ":thing1", ":thing_a",
":THING", ":thing!", ":thing=", ":thing?", ":t?"]);
assertInvalidTokens(this.tokenizer, "string",
[":", ":@", ":$", ":1", ":1thing", ":th?ing", ":thi=ng", ":1thing",
":th!ing", ":thing#"]);
},
"test: namespaces aren't symbols" : function() {
var line = "Namespaced::Class";
var tokens = this.tokenizer.getLineTokens(line, "start").tokens;
assert.equal(3, tokens.length);
assert.equal("variable.class", tokens[0].type);
assert.equal("text", tokens[1].type);
assert.equal("variable.class", tokens[2].type);
},
"test: hex tokenizer" : function() {
assertValidTokens(this.tokenizer, "constant.numeric",
["0x9a", "0XA1", "0x9_a"]);
assertInvalidTokens(this.tokenizer, "constant.numeric",
["0x", "0x_9a", "0x9a_"]);
},
"test: float tokenizer" : function() {
assertValidTokens(this.tokenizer, "constant.numeric",
["1", "+1", "-1", "12_345", "0.000_1"]);
assertInvalidTokens(this.tokenizer, "constant.numeric",
["_", "_1", "1_", "1_.0", "0._1"]);
}
};
function assertValidTokens(tokenizer, tokenType, validTokens) {
for (var i = 0, length = validTokens.length; i < length; i++) {
var validToken = validTokens[i],
tokens = tokenizer.getLineTokens(validToken, "start").tokens;
assert.equal(tokens[0].value, validToken,
'"' + validToken + '" should be one token');
assert.equal(tokens[0].type, tokenType,
'"' + validToken + '" should be a "' + tokenType + '" token');
}
}
function assertInvalidTokens(tokenizer, tokenType, invalidTokens) {
for (var i = 0, length = invalidTokens.length; i < length; i++) {
var invalidToken = invalidTokens[i],
tokens = tokenizer.getLineTokens(invalidToken, "start").tokens;
assert.ok(tokens[0].type !== tokenType || tokens[0].value !== invalidToken,
'"' + invalidToken + '" is not a valid "' + tokenType + '"');
}
}
});
if (typeof module !== "undefined" && module === require.main) {
require("asyncjs").test.testcase(module.exports).exec()
}

130
ace/mode/scad.js Normal file
View file

@ -0,0 +1,130 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Gastón Kleiman <gaston.kleiman AT gmail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("pilot/oop");
var TextMode = require("ace/mode/text").Mode;
var Tokenizer = require("ace/tokenizer").Tokenizer;
var scadHighlightRules = require("ace/mode/scad_highlight_rules").scadHighlightRules;
var MatchingBraceOutdent = require("ace/mode/matching_brace_outdent").MatchingBraceOutdent;
var Range = require("ace/range").Range;
var CstyleBehaviour = require("ace/mode/behaviour/cstyle").CstyleBehaviour;
var Mode = function() {
this.$tokenizer = new Tokenizer(new scadHighlightRules().getRules());
this.$outdent = new MatchingBraceOutdent();
this.$behaviour = new CstyleBehaviour();
};
oop.inherits(Mode, TextMode);
(function() {
this.toggleCommentLines = function(state, doc, startRow, endRow) {
var outdent = true;
var outentedRows = [];
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;
});

View file

@ -1,47 +1,59 @@
/* ***** BEGIN LICENSE BLOCK ***** /* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
* *
* Copyright (c) 2010, Ajax.org B.V. * The contents of this file are subject to the Mozilla Public License Version
* All rights reserved. * 1.1 (the "License"); you may not use this file except in compliance with
* * the License. You may obtain a copy of the License at
* Redistribution and use in source and binary forms, with or without * http://www.mozilla.org/MPL/
* modification, are permitted provided that the following conditions are met: *
* * Redistributions of source code must retain the above copyright * Software distributed under the License is distributed on an "AS IS" basis,
* notice, this list of conditions and the following disclaimer. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* * Redistributions in binary form must reproduce the above copyright * for the specific language governing rights and limitations under the
* notice, this list of conditions and the following disclaimer in the * License.
* documentation and/or other materials provided with the distribution. *
* * Neither the name of Ajax.org B.V. nor the * The Original Code is Ajax.org Code Editor (ACE).
* names of its contributors may be used to endorse or promote products *
* derived from this software without specific prior written permission. * The Initial Developer of the Original Code is
* * Ajax.org B.V.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * Portions created by the Initial Developer are Copyright (C) 2010
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * the Initial Developer. All Rights Reserved.
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY * Contributor(s):
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * Fabian Jakobs <fabian AT ajax DOT org>
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * Gastón Kleiman <gaston.kleiman AT gmail DOT com>
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * Based on Bespin's C/C++ Syntax Plugin by Marc McIntyre.
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
* *
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) { define(function(require, exports, module) {
"use strict";
var oop = require("../lib/oop"); var oop = require("pilot/oop");
var lang = require("../lib/lang"); var lang = require("pilot/lang");
var DocCommentHighlightRules = require("./doc_comment_highlight_rules").DocCommentHighlightRules; var DocCommentHighlightRules = require("ace/mode/doc_comment_highlight_rules").DocCommentHighlightRules;
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
var scadHighlightRules = function() { var scadHighlightRules = function() {
var keywordMapper = this.createKeywordMapper({
"variable.language": "this", var keywords = lang.arrayToMap(
"keyword": "module|if|else|for", ("module|if|else|for").split("|")
"constant.language": "NULL" );
}, "identifier");
var buildinConstants = lang.arrayToMap(
("NULL").split("|")
);
// regexp must not have capturing parentheses. Use (?:) instead. // regexp must not have capturing parentheses. Use (?:) instead.
// regexps are ordered -> the first match is used // regexps are ordered -> the first match is used
@ -52,9 +64,10 @@ var scadHighlightRules = function() {
token : "comment", token : "comment",
regex : "\\/\\/.*$" regex : "\\/\\/.*$"
}, },
DocCommentHighlightRules.getStartRule("start"), new DocCommentHighlightRules().getStartRule("start"),
{ {
token : "comment", // multi line comment token : "comment", // multi line comment
merge : true,
regex : "\\/\\*", regex : "\\/\\*",
next : "comment" next : "comment"
}, { }, {
@ -83,17 +96,26 @@ var scadHighlightRules = function() {
}, { }, {
token : "keyword", // pre-compiler directivs token : "keyword", // pre-compiler directivs
regex : "(?:use|include)" regex : "(?:use|include)"
}, { }, {
token : keywordMapper, token : function(value) {
if (value == "this")
return "variable.language";
else if (keywords.hasOwnProperty(value))
return "keyword";
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
else
return "identifier";
},
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, { }, {
token : "keyword.operator", token : "keyword.operator",
regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|==|=|!=|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|new|delete|typeof|void)" regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|==|=|!=|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|new|delete|typeof|void)"
}, { }, {
token : "paren.lparen", token : "lparen",
regex : "[[({]" regex : "[[({]"
}, { }, {
token : "paren.rparen", token : "rparen",
regex : "[\\])}]" regex : "[\\])}]"
}, { }, {
token : "text", token : "text",
@ -107,6 +129,7 @@ var scadHighlightRules = function() {
next : "start" next : "start"
}, { }, {
token : "comment", // comment spanning whole line token : "comment", // comment spanning whole line
merge : true,
regex : ".+" regex : ".+"
} }
], ],
@ -117,6 +140,7 @@ var scadHighlightRules = function() {
next : "start" next : "start"
}, { }, {
token : "string", token : "string",
merge : true,
regex : '.+' regex : '.+'
} }
], ],
@ -127,13 +151,14 @@ var scadHighlightRules = function() {
next : "start" next : "start"
}, { }, {
token : "string", token : "string",
merge : true,
regex : '.+' regex : '.+'
} }
] ]
}; };
this.embedRules(DocCommentHighlightRules, "doc-", this.embedRules(DocCommentHighlightRules, "doc-",
[ DocCommentHighlightRules.getEndRule("start") ]); [ new DocCommentHighlightRules().getEndRule("start") ]);
}; };
oop.inherits(scadHighlightRules, TextHighlightRules); oop.inherits(scadHighlightRules, TextHighlightRules);

Some files were not shown because too many files have changed in this diff Show more