diff --git a/codemirror-2.36/.gitignore b/codemirror-2.36/.gitignore
new file mode 100644
index 00000000..28b5e414
--- /dev/null
+++ b/codemirror-2.36/.gitignore
@@ -0,0 +1,2 @@
+/node_modules
+/npm-debug.log
\ No newline at end of file
diff --git a/codemirror-2.36/.travis.yml b/codemirror-2.36/.travis.yml
new file mode 100644
index 00000000..baa0031d
--- /dev/null
+++ b/codemirror-2.36/.travis.yml
@@ -0,0 +1,3 @@
+language: node_js
+node_js:
+ - 0.8
diff --git a/codemirror-2.36/LICENSE b/codemirror-2.36/LICENSE
new file mode 100644
index 00000000..3916e96b
--- /dev/null
+++ b/codemirror-2.36/LICENSE
@@ -0,0 +1,23 @@
+Copyright (C) 2012 by Marijn Haverbeke Styling the current cursor line. On changes to the content of the above editor, a (crude) script
+tries to auto-detect the language used, and switches the editor to
+either JavaScript or Scheme mode based on that.CodeMirror: Active Line Demo
+
+
+
+
+
+ CodeMirror: Mode-Changing demo
+
+
+
+Close-Tag Demo
+
+
Press ctrl-space to activate autocompletion. See +the code (here +and here) to figure out +how it works.
+ + + + diff --git a/codemirror-2.36/demo/emacs.html b/codemirror-2.36/demo/emacs.html new file mode 100644 index 00000000..b37a46b0 --- /dev/null +++ b/codemirror-2.36/demo/emacs.html @@ -0,0 +1,60 @@ + + + + +The emacs keybindings are enabled by
+including keymap/emacs.js and setting
+the keyMap
option to "emacs"
. Because
+CodeMirror's internal API is quite different from Emacs, they are only
+a loose approximation of actual emacs bindings, though.
Also note that a lot of browsers disallow certain keys from being +captured. For example, Chrome blocks both Ctrl-W and Ctrl-N, with the +result that idiomatic use of Emacs keys will constantly close your tab +or open a new window.
+ + + + + diff --git a/codemirror-2.36/demo/folding.html b/codemirror-2.36/demo/folding.html new file mode 100644 index 00000000..39a6a60e --- /dev/null +++ b/codemirror-2.36/demo/folding.html @@ -0,0 +1,62 @@ + + + + +Demonstration of code folding using the code
+ in foldcode.js
.
+ Press ctrl-q or click on the gutter to fold a block, again
+ to unfold.
Select a piece of code and click one of the links below to apply automatic formatting to the selected text or comment/uncomment the selected text. Note that the formatting behavior depends on the current block's mode. +
+ + Autoformat Selected + + | ++ + Comment Selected + + | ++ + Uncomment Selected + + | +
Press F11 when cursor is in the editor to toggle full screen editing. Esc can also be used to exit full screen editing.
+ + diff --git a/codemirror-2.36/demo/loadmode.html b/codemirror-2.36/demo/loadmode.html new file mode 100644 index 00000000..8813ea85 --- /dev/null +++ b/codemirror-2.36/demo/loadmode.html @@ -0,0 +1,40 @@ + + + + ++ + + + diff --git a/codemirror-2.36/demo/marker.html b/codemirror-2.36/demo/marker.html new file mode 100644 index 00000000..7bc6c6de --- /dev/null +++ b/codemirror-2.36/demo/marker.html @@ -0,0 +1,53 @@ + + + + +
Click the line-number gutter to add or remove 'breakpoints'.
+ + + + + diff --git a/codemirror-2.36/demo/matchhighlighter.html b/codemirror-2.36/demo/matchhighlighter.html new file mode 100644 index 00000000..5eef08d8 --- /dev/null +++ b/codemirror-2.36/demo/matchhighlighter.html @@ -0,0 +1,38 @@ + + + + +Highlight matches of selected text on select
+ + + diff --git a/codemirror-2.36/demo/multiplex.html b/codemirror-2.36/demo/multiplex.html new file mode 100644 index 00000000..25fffd32 --- /dev/null +++ b/codemirror-2.36/demo/multiplex.html @@ -0,0 +1,60 @@ + + + + +Demonstration of a multiplexing mode, which, at certain
+ boundary strings, switches to one or more inner modes. The out
+ (HTML) mode does not get fed the content of the <<
+ >>
blocks. See
+ the manual and
+ the source for more
+ information.
Demonstration of a mode that parses HTML, highlighting
+ the Mustache templating
+ directives inside of it by using the code
+ in overlay.js
. View
+ source to see the 15 lines of code needed to accomplish this.
By setting a few CSS properties, CodeMirror can be made to +automatically resize to fit its content.
+ + + + + diff --git a/codemirror-2.36/demo/runmode.html b/codemirror-2.36/demo/runmode.html new file mode 100644 index 00000000..53ac04f9 --- /dev/null +++ b/codemirror-2.36/demo/runmode.html @@ -0,0 +1,50 @@ + + + + +Running a CodeMirror mode outside of the editor.
+ The CodeMirror.runMode
function, defined
+ in lib/runmode.js
takes the following arguments:
text (string)
mode (mode spec)
output (function or DOM node)
null
for unstyled tokens). If it is a DOM node,
+ the tokens will be converted to span
elements as in
+ an editor, and inserted into the node
+ (through innerHTML
).Demonstration of primitive search/replace functionality. The + keybindings (which can be overridden by custom keymaps) are:
+Searching is enabled by + including lib/util/search.js + and lib/util/searchcursor.js. + For good-looking input dialogs, you also want to include + lib/util/dialog.js + and lib/util/dialog.css.
+ + diff --git a/codemirror-2.36/demo/theme.html b/codemirror-2.36/demo/theme.html new file mode 100644 index 00000000..963a776e --- /dev/null +++ b/codemirror-2.36/demo/theme.html @@ -0,0 +1,81 @@ + + + + +Select a theme: +
+ + + + diff --git a/codemirror-2.36/demo/vim.html b/codemirror-2.36/demo/vim.html new file mode 100644 index 00000000..6813cb37 --- /dev/null +++ b/codemirror-2.36/demo/vim.html @@ -0,0 +1,53 @@ + + + + +The vim keybindings are enabled by
+including keymap/vim.js and setting
+the keyMap
option to "vim"
. Because
+CodeMirror's internal API is quite different from Vim, they are only
+a loose approximation of actual vim bindings, though.
Tabs inside the editor are spans with the
+class cm-tab
, and can be styled.
+
+
+
+
+
diff --git a/codemirror-2.36/demo/xmlcomplete.html b/codemirror-2.36/demo/xmlcomplete.html
new file mode 100644
index 00000000..baa9aa22
--- /dev/null
+++ b/codemirror-2.36/demo/xmlcomplete.html
@@ -0,0 +1,71 @@
+
+
+
Type '<' or space inside tag or + press ctrl-space to activate autocompletion. See + the code (here + and here) to figure out how + it works.
+ + + + diff --git a/codemirror-2.36/doc/baboon.png b/codemirror-2.36/doc/baboon.png new file mode 100644 index 00000000..55d97f70 Binary files /dev/null and b/codemirror-2.36/doc/baboon.png differ diff --git a/codemirror-2.36/doc/baboon_vector.svg b/codemirror-2.36/doc/baboon_vector.svg new file mode 100644 index 00000000..dc1667af --- /dev/null +++ b/codemirror-2.36/doc/baboon_vector.svg @@ -0,0 +1,153 @@ + + + + \ No newline at end of file diff --git a/codemirror-2.36/doc/compress.html b/codemirror-2.36/doc/compress.html new file mode 100644 index 00000000..1667c334 --- /dev/null +++ b/codemirror-2.36/doc/compress.html @@ -0,0 +1,168 @@ + + + + ++/* Script compression + helper */ ++
To optimize loading CodeMirror, especially when including a + bunch of different modes, it is recommended that you combine and + minify (and preferably also gzip) the scripts. This page makes + those first two steps very easy. Simply select the version and + scripts you need in the form below, and + click Compress to download the minified script + file.
+ + + + + + + diff --git a/codemirror-2.36/doc/docs.css b/codemirror-2.36/doc/docs.css new file mode 100644 index 00000000..547b6175 --- /dev/null +++ b/codemirror-2.36/doc/docs.css @@ -0,0 +1,167 @@ +body { + font-family: Droid Sans, Arial, sans-serif; + line-height: 1.5; + max-width: 64.3em; + margin: 3em auto; + padding: 0 1em; +} + +h1 { + letter-spacing: -3px; + font-size: 3.23em; + font-weight: bold; + margin: 0; +} + +h2 { + font-size: 1.23em; + font-weight: bold; + margin: .5em 0; + letter-spacing: -1px; +} + +h3 { + font-size: 1em; + font-weight: bold; + margin: .4em 0; +} + +pre { + background-color: #eee; + -moz-border-radius: 6px; + -webkit-border-radius: 6px; + border-radius: 6px; + padding: 1em; +} + +pre.code { + margin: 0 1em; +} + +.grey { + background-color: #eee; + border-radius: 6px; + margin-bottom: 1.65em; + margin-top: 0.825em; + padding: 0.825em 1.65em; + position: relative; +} + +img.logo { + position: absolute; + right: -1em; + bottom: 4px; + max-width: 23.6875em; /* Scale image down with text to prevent clipping */ +} + +.grey > pre { + background:none; + border-radius:0; + padding:0; + margin:0; + font-size:2.2em; + line-height:1.2em; +} + +a:link, a:visited, .quasilink { + color: #df0019; + cursor: pointer; + text-decoration: none; +} + +a:hover, .quasilink:hover { + color: #800004; +} + +h1 a:link, h1 a:visited, h1 a:hover { + color: black; +} + +ul { + margin: 0; + padding-left: 1.2em; +} + +a.download { + color: white; + background-color: #df0019; + width: 100%; + display: block; + text-align: center; + font-size: 1.23em; + font-weight: bold; + text-decoration: none; + -moz-border-radius: 6px; + -webkit-border-radius: 6px; + border-radius: 6px; + padding: .5em 0; + margin-bottom: 1em; +} + +a.download:hover { + background-color: #bb0010; +} + +.rel { + margin-bottom: 0; +} + +.rel-note { + color: #777; + font-size: .9em; + margin-top: .1em; +} + +.logo-braces { + color: #df0019; + position: relative; + top: -4px; +} + +.blk { + float: left; +} + +.left { + margin-right: 20.68em; + max-width: 37em; + padding-right: 6.53em; + padding-bottom: 1em; +} + +.left1 { + width: 15.24em; + padding-right: 6.45em; +} + +.left2 { + max-width: 15.24em; +} + +.right { + width: 20.68em; + margin-left: -20.68em; +} + +.leftbig { + width: 42.44em; + padding-right: 6.53em; +} + +.rightsmall { + width: 15.24em; +} + +.clear:after { + visibility: hidden; + display: block; + font-size: 0; + content: " "; + clear: both; + height: 0; +} +.clear { display: inline-block; } +/* start commented backslash hack \*/ +* html .clear { height: 1%; } +.clear { display: block; } +/* close commented backslash hack */ diff --git a/codemirror-2.36/doc/internals.html b/codemirror-2.36/doc/internals.html new file mode 100644 index 00000000..d8594198 --- /dev/null +++ b/codemirror-2.36/doc/internals.html @@ -0,0 +1,497 @@ + + + + ++/* (Re-) Implementing A Syntax- + Highlighting Editor in JavaScript */ ++
+ Topic: JavaScript, code editor implementation
+ Author: Marijn Haverbeke
+ Date: March 2nd 2011 (updated November 13th 2011)
+
This is a followup to +my Brutal Odyssey to the +Dark Side of the DOM Tree story. That one describes the +mind-bending process of implementing (what would become) CodeMirror 1. +This one describes the internals of CodeMirror 2, a complete rewrite +and rethink of the old code base. I wanted to give this piece another +Hunter Thompson copycat subtitle, but somehow that would be out of +place—the process this time around was one of straightforward +engineering, requiring no serious mind-bending whatsoever.
+ +So, what is wrong with CodeMirror 1? I'd estimate, by mailing list +activity and general search-engine presence, that it has been +integrated into about a thousand systems by now. The most prominent +one, since a few weeks, +being Google +code's project hosting. It works, and it's being used widely. + +
Still, I did not start replacing it because I was bored. CodeMirror
+1 was heavily reliant on designMode
+or contentEditable
(depending on the browser). Neither of
+these are well specified (HTML5 tries
+to specify
+their basics), and, more importantly, they tend to be one of the more
+obscure and buggy areas of browser functionality—CodeMirror, by using
+this functionality in a non-typical way, was constantly running up
+against browser bugs. WebKit wouldn't show an empty line at the end of
+the document, and in some releases would suddenly get unbearably slow.
+Firefox would show the cursor in the wrong place. Internet Explorer
+would insist on linkifying everything that looked like a URL or email
+address, a behaviour that can't be turned off. Some bugs I managed to
+work around (which was often a frustrating, painful process), others,
+such as the Firefox cursor placement, I gave up on, and had to tell
+user after user that they were known problems, but not something I
+could help.
Also, there is the fact that designMode
(which seemed
+to be less buggy than contentEditable
in Webkit and
+Firefox, and was thus used by CodeMirror 1 in those browsers) requires
+a frame. Frames are another tricky area. It takes some effort to
+prevent getting tripped up by domain restrictions, they don't
+initialize synchronously, behave strangely in response to the back
+button, and, on several browsers, can't be moved around the DOM
+without having them re-initialize. They did provide a very nice way to
+namespace the library, though—CodeMirror 1 could freely pollute the
+namespace inside the frame.
Finally, working with an editable document means working with
+selection in arbitrary DOM structures. Internet Explorer (8 and
+before) has an utterly different (and awkward) selection API than all
+of the other browsers, and even among the different implementations of
+document.selection
, details about how exactly a selection
+is represented vary quite a bit. Add to that the fact that Opera's
+selection support tended to be very buggy until recently, and you can
+imagine why CodeMirror 1 contains 700 lines of selection-handling
+code.
And that brings us to the main issue with the CodeMirror 1 +code base: The proportion of browser-bug-workarounds to real +application code was getting dangerously high. By building on top of a +few dodgy features, I put the system in a vulnerable position—any +incompatibility and bugginess in these features, I had to paper over +with my own code. Not only did I have to do some serious stunt-work to +get it to work on older browsers (as detailed in the +previous story), things +also kept breaking in newly released versions, requiring me to come up +with new scary hacks in order to keep up. This was starting +to lose its appeal.
+ +What CodeMirror 2 does is try to sidestep most of the hairy hacks +that came up in version 1. I owe a lot to the +ACE editor for inspiration on how to +approach this.
+ +I absolutely did not want to be completely reliant on key events to +generate my input. Every JavaScript programmer knows that key event +information is horrible and incomplete. Some people (most awesomely +Mihai Bazon with Ymacs) have been able +to build more or less functioning editors by directly reading key +events, but it takes a lot of work (the kind of never-ending, fragile +work I described earlier), and will never be able to properly support +things like multi-keystoke international character +input. [see below for caveat]
+ +So what I do is focus a hidden textarea, and let the browser +believe that the user is typing into that. What we show to the user is +a DOM structure we built to represent his document. If this is updated +quickly enough, and shows some kind of believable cursor, it feels +like a real text-input control.
+ +Another big win is that this DOM representation does not have to
+span the whole document. Some CodeMirror 1 users insisted that they
+needed to put a 30 thousand line XML document into CodeMirror. Putting
+all that into the DOM takes a while, especially since, for some
+reason, an editable DOM tree is slower than a normal one on most
+browsers. If we have full control over what we show, we must only
+ensure that the visible part of the document has been added, and can
+do the rest only when needed. (Fortunately, the onscroll
+event works almost the same on all browsers, and lends itself well to
+displaying things only as they are scrolled into view.)
ACE uses its hidden textarea only as a text input shim, and does +all cursor movement and things like text deletion itself by directly +handling key events. CodeMirror's way is to let the browser do its +thing as much as possible, and not, for example, define its own set of +key bindings. One way to do this would have been to have the whole +document inside the hidden textarea, and after each key event update +the display DOM to reflect what's in that textarea.
+ +That'd be simple, but it is not realistic. For even medium-sized +document the editor would be constantly munging huge strings, and get +terribly slow. What CodeMirror 2 does is put the current selection, +along with an extra line on the top and on the bottom, into the +textarea.
+ +This means that the arrow keys (and their ctrl-variations), home, +end, etcetera, do not have to be handled specially. We just read the +cursor position in the textarea, and update our cursor to match it. +Also, copy and paste work pretty much for free, and people get their +native key bindings, without any special work on my part. For example, +I have emacs key bindings configured for Chrome and Firefox. There is +no way for a script to detect this. [no longer the case]
+ +Of course, since only a small part of the document sits in the +textarea, keys like page up and ctrl-end won't do the right thing. +CodeMirror is catching those events and handling them itself.
+ +Getting and setting the selection range of a textarea in modern
+browsers is trivial—you just use the selectionStart
+and selectionEnd
properties. On IE you have to do some
+insane stuff with temporary ranges and compensating for the fact that
+moving the selection by a 'character' will treat \r\n as a single
+character, but even there it is possible to build functions that
+reliably set and get the selection range.
But consider this typical case: When I'm somewhere in my document, +press shift, and press the up arrow, something gets selected. Then, if +I, still holding shift, press the up arrow again, the top of my +selection is adjusted. The selection remembers where its head +and its anchor are, and moves the head when we shift-move. +This is a generally accepted property of selections, and done right by +every editing component built in the past twenty years.
+ +But not something that the browser selection APIs expose.
+ +Great. So when someone creates an 'upside-down' selection, the next +time CodeMirror has to update the textarea, it'll re-create the +selection as an 'upside-up' selection, with the anchor at the top, and +the next cursor motion will behave in an unexpected way—our second +up-arrow press in the example above will not do anything, since it is +interpreted in exactly the same way as the first.
+ +No problem. We'll just, ehm, detect that the selection is +upside-down (you can tell by the way it was created), and then, when +an upside-down selection is present, and a cursor-moving key is +pressed in combination with shift, we quickly collapse the selection +in the textarea to its start, allow the key to take effect, and then +combine its new head with its old anchor to get the real +selection.
+ +In short, scary hacks could not be avoided entirely in CodeMirror +2.
+ +And, the observant reader might ask, how do you even know that a +key combo is a cursor-moving combo, if you claim you support any +native key bindings? Well, we don't, but we can learn. The editor +keeps a set known cursor-movement combos (initialized to the +predictable defaults), and updates this set when it observes that +pressing a certain key had (only) the effect of moving the cursor. +This, of course, doesn't work if the first time the key is used was +for extending an inverted selection, but it works most of the +time.
+ +One thing that always comes up when you have a complicated internal +state that's reflected in some user-visible external representation +(in this case, the displayed code and the textarea's content) is +keeping the two in sync. The naive way is to just update the display +every time you change your state, but this is not only error prone +(you'll forget), it also easily leads to duplicate work on big, +composite operations. Then you start passing around flags indicating +whether the display should be updated in an attempt to be efficient +again and, well, at that point you might as well give up completely.
+ +I did go down that road, but then switched to a much simpler model: +simply keep track of all the things that have been changed during an +action, and then, only at the end, use this information to update the +user-visible display.
+ +CodeMirror uses a concept of operations, which start by
+calling a specific set-up function that clears the state and end by
+calling another function that reads this state and does the required
+updating. Most event handlers, and all the user-visible methods that
+change state are wrapped like this. There's a method
+called operation
that accepts a function, and returns
+another function that wraps the given function as an operation.
It's trivial to extend this (as CodeMirror does) to detect nesting, +and, when an operation is started inside an operation, simply +increment the nesting count, and only do the updating when this count +reaches zero again.
+ +If we have a set of changed ranges and know the currently shown +range, we can (with some awkward code to deal with the fact that +changes can add and remove lines, so we're dealing with a changing +coordinate system) construct a map of the ranges that were left +intact. We can then compare this map with the part of the document +that's currently visible (based on scroll offset and editor height) to +determine whether something needs to be updated.
+ +CodeMirror uses two update algorithms—a full refresh, where it just +discards the whole part of the DOM that contains the edited text and +rebuilds it, and a patch algorithm, where it uses the information +about changed and intact ranges to update only the out-of-date parts +of the DOM. When more than 30 percent (which is the current heuristic, +might change) of the lines need to be updated, the full refresh is +chosen (since it's faster to do than painstakingly finding and +updating all the changed lines), in the other case it does the +patching (so that, if you scroll a line or select another character, +the whole screen doesn't have to be +re-rendered). [the full-refresh +algorithm was dropped, it wasn't really faster than the patching +one]
+ +All updating uses innerHTML
rather than direct DOM
+manipulation, since that still seems to be by far the fastest way to
+build documents. There's a per-line function that combines the
+highlighting, marking, and
+selection info for that line into a snippet of HTML. The patch updater
+uses this to reset individual lines, the refresh updater builds an
+HTML chunk for the whole visible document at once, and then uses a
+single innerHTML
update to do the refresh.
When I wrote CodeMirror 1, I +thought interruptable +parsers were a hugely scary and complicated thing, and I used a +bunch of heavyweight abstractions to keep this supposed complexity +under control: parsers +were iterators +that consumed input from another iterator, and used funny +closure-resetting tricks to copy and resume themselves.
+ +This made for a rather nice system, in that parsers formed strictly +separate modules, and could be composed in predictable ways. +Unfortunately, it was quite slow (stacking three or four iterators on +top of each other), and extremely intimidating to people not used to a +functional programming style.
+ +With a few small changes, however, we can keep all those +advantages, but simplify the API and make the whole thing less +indirect and inefficient. CodeMirror +2's mode API uses explicit state +objects, and makes the parser/tokenizer a function that simply takes a +state and a character stream abstraction, advances the stream one +token, and returns the way the token should be styled. This state may +be copied, optionally in a mode-defined way, in order to be able to +continue a parse at a given point. Even someone who's never touched a +lambda in his life can understand this approach. Additionally, far +fewer objects are allocated in the course of parsing now.
+ +The biggest speedup comes from the fact that the parsing no longer +has to touch the DOM though. In CodeMirror 1, on an older browser, you +could see the parser work its way through the document, +managing some twenty lines in each 50-millisecond time slice it got. It +was reading its input from the DOM, and updating the DOM as it went +along, which any experienced JavaScript programmer will immediately +spot as a recipe for slowness. In CodeMirror 2, the parser usually +finishes the whole document in a single 100-millisecond time slice—it +manages some 1500 lines during that time on Chrome. All it has to do +is munge strings, so there is no real reason for it to be slow +anymore.
+ +Given all this, what can you expect from CodeMirror 2?
+ +iframe
nodes aren't
+really known for respecting document flow. Now that an editor instance
+is a plain div
element, it is much easier to size it to
+fit the surrounding elements. You don't even have to make it scroll if
+you do not want to.On the downside, a CodeMirror 2 instance is not a native +editable component. Though it does its best to emulate such a +component as much as possible, there is functionality that browsers +just do not allow us to hook into. Doing select-all from the context +menu, for example, is not currently detected by CodeMirror.
+ +[Updates from November 13th 2011] Recently, I've made +some changes to the codebase that cause some of the text above to no +longer be current. I've left the text intact, but added markers at the +passages that are now inaccurate. The new situation is described +below.
+ +The original implementation of CodeMirror 2 represented the
+document as a flat array of line objects. This worked well—splicing
+arrays will require the part of the array after the splice to be
+moved, but this is basically just a simple memmove
of a
+bunch of pointers, so it is cheap even for huge documents.
However, I recently added line wrapping and code folding (line +collapsing, basically). Once lines start taking up a non-constant +amount of vertical space, looking up a line by vertical position +(which is needed when someone clicks the document, and to determine +the visible part of the document during scrolling) can only be done +with a linear scan through the whole array, summing up line heights as +you go. Seeing how I've been going out of my way to make big documents +fast, this is not acceptable.
+ +The new representation is based on a B-tree. The leaves of the tree +contain arrays of line objects, with a fixed minimum and maximum size, +and the non-leaf nodes simply hold arrays of child nodes. Each node +stores both the amount of lines that live below them and the vertical +space taken up by these lines. This allows the tree to be indexed both +by line number and by vertical position, and all access has +logarithmic complexity in relation to the document size.
+ +I gave line objects and tree nodes parent pointers, to the node +above them. When a line has to update its height, it can simply walk +these pointers to the top of the tree, adding or subtracting the +difference in height from each node it encounters. The parent pointers +also make it cheaper (in complexity terms, the difference is probably +tiny in normal-sized documents) to find the current line number when +given a line object. In the old approach, the whole document array had +to be searched. Now, we can just walk up the tree and count the sizes +of the nodes coming before us at each level.
+ +I chose B-trees, not regular binary trees, mostly because they +allow for very fast bulk insertions and deletions. When there is a big +change to a document, it typically involves adding, deleting, or +replacing a chunk of subsequent lines. In a regular balanced tree, all +these inserts or deletes would have to be done separately, which could +be really expensive. In a B-tree, to insert a chunk, you just walk +down the tree once to find where it should go, insert them all in one +shot, and then break up the node if needed. This breaking up might +involve breaking up nodes further up, but only requires a single pass +back up the tree. For deletion, I'm somewhat lax in keeping things +balanced—I just collapse nodes into a leaf when their child count goes +below a given number. This means that there are some weird editing +patterns that may result in a seriously unbalanced tree, but even such +an unbalanced tree will perform well, unless you spend a day making +strangely repeating edits to a really big document.
+ +Above, I claimed that directly catching key +events for things like cursor movement is impractical because it +requires some browser-specific kludges. I then proceeded to explain +some awful hacks that were needed to make it +possible for the selection changes to be detected through the +textarea. In fact, the second hack is about as bad as the first.
+ +On top of that, in the presence of user-configurable tab sizes and +collapsed and wrapped lines, lining up cursor movement in the textarea +with what's visible on the screen becomes a nightmare. Thus, I've +decided to move to a model where the textarea's selection is no longer +depended on.
+ +So I moved to a model where all cursor movement is handled by my +own code. This adds support for a goal column, proper interaction of +cursor movement with collapsed lines, and makes it possible for +vertical movement to move through wrapped lines properly, instead of +just treating them like non-wrapped lines.
+ +The key event handlers now translate the key event into a string,
+something like Ctrl-Home
or Shift-Cmd-R
, and
+use that string to look up an action to perform. To make keybinding
+customizable, this lookup goes through
+a table, using a scheme that
+allows such tables to be chained together (for example, the default
+Mac bindings fall through to a table named 'emacsy', which defines
+basic Emacs-style bindings like Ctrl-F
, and which is also
+used by the custom Emacs bindings).
A new
+option extraKeys
+allows ad-hoc keybindings to be defined in a much nicer way than what
+was possible with the
+old onKeyEvent
+callback. You simply provide an object mapping key identifiers to
+functions, instead of painstakingly looking at raw key events.
Built-in commands map to strings, rather than functions, for
+example "goLineUp"
is the default action bound to the up
+arrow key. This allows new keymaps to refer to them without
+duplicating any code. New commands can be defined by assigning to
+the CodeMirror.commands
object, which maps such commands
+to functions.
The hidden textarea now only holds the current selection, with no +extra characters around it. This has a nice advantage: polling for +input becomes much, much faster. If there's a big selection, this text +does not have to be read from the textarea every time—when we poll, +just noticing that something is still selected is enough to tell us +that no new text was typed.
+ +The reason that cheap polling is important is that many browsers do
+not fire useful events on IME (input method engine) input, which is
+the thing where people inputting a language like Japanese or Chinese
+use multiple keystrokes to create a character or sequence of
+characters. Most modern browsers fire input
when the
+composing is finished, but many don't fire anything when the character
+is updated during composition. So we poll, whenever the
+editor is focused, to provide immediate updates of the display.
+/* User manual and + reference guide */ ++
CodeMirror is a code-editor component that can be embedded in + Web pages. The code library provides only the editor + component, no accompanying buttons, auto-completion, or other IDE + functionality. It does provide a rich API on top of which such + functionality can be straightforwardly implemented. See + the add-ons included in the distribution, + and + the CodeMirror + UI project, for reusable implementations of extra features.
+ +CodeMirror works with language-specific modes. Modes are
+ JavaScript programs that help color (and optionally indent) text
+ written in a given language. The distribution comes with a number
+ of modes (see the mode/
directory), and it isn't hard
+ to write new ones for other languages.
The easiest way to use CodeMirror is to simply load the script
+ and style sheet found under lib/
in the distribution,
+ plus a mode script from one of the mode/
directories
+ and a theme stylesheet from theme/
. (See
+ also the compression helper.) For
+ example:
<script src="lib/codemirror.js"></script> +<link rel="stylesheet" href="../lib/codemirror.css"> +<script src="mode/javascript/javascript.js"></script>+ +
Having done this, an editor instance can be created like + this:
+ +var myCodeMirror = CodeMirror(document.body);+ +
The editor will be appended to the document body, will start
+ empty, and will use the mode that we loaded. To have more control
+ over the new editor, a configuration object can be passed
+ to CodeMirror
as a second argument:
var myCodeMirror = CodeMirror(document.body, { + value: "function myScript(){return 100;}\n", + mode: "javascript" +});+ +
This will initialize the editor with a piece of code already in + it, and explicitly tell it to use the JavaScript mode (which is + useful when multiple modes are loaded). + See below for a full discussion of the + configuration options that CodeMirror accepts.
+ +In cases where you don't want to append the editor to an
+ element, and need more control over the way it is inserted, the
+ first argument to the CodeMirror
function can also
+ be a function that, when given a DOM element, inserts it into the
+ document somewhere. This could be used to, for example, replace a
+ textarea with a real editor:
var myCodeMirror = CodeMirror(function(elt) { + myTextArea.parentNode.replaceChild(elt, myTextArea); +}, {value: myTextArea.value});+ +
However, for this use case, which is a common way to use + CodeMirror, the library provides a much more powerful + shortcut:
+ +var myCodeMirror = CodeMirror.fromTextArea(myTextArea);+ +
This will, among other things, ensure that the textarea's value + is updated when the form (if it is part of a form) is submitted. + See the API reference for a full + description of this method.
+ +Both the CodeMirror
function and
+ its fromTextArea
method take as second (optional)
+ argument an object containing configuration options. Any option
+ not supplied like this will be taken
+ from CodeMirror.defaults
, an object containing the
+ default options. You can update this object to change the defaults
+ on your page.
Options are not checked in any way, so setting bogus option + values is bound to lead to odd errors.
+ +These are the supported options:
+ +value (string)
mode (string or object)
name
property that names the mode (for
+ example {name: "javascript", json: true}
). The demo
+ pages for each mode contain information about what configuration
+ parameters the mode supports. You can ask CodeMirror which modes
+ and MIME types are loaded with
+ the CodeMirror.listModes
+ and CodeMirror.listMIMEs
functions.theme (string)
.cm-s-[name]
+ styles is loaded (see
+ the theme
directory in the
+ distribution). The default is "default"
, for which
+ colors are included in codemirror.css
. It is
+ possible to use multiple theming classes at once—for
+ example "foo bar"
will assign both
+ the cm-s-foo
and the cm-s-bar
classes
+ to the editor.indentUnit (integer)
smartIndent (boolean)
tabSize (integer)
indentWithTabs (boolean)
tabSize
+ spaces should be replaced by N tabs. Default is false.electricChars (boolean)
autoClearEmptyLines (boolean)
keyMap (string)
"default"
, which is the only keymap defined
+ in codemirror.js
itself. Extra keymaps are found in
+ the keymap
directory. See
+ the section on keymaps for more
+ information.extraKeys (object)
keyMap
. Should be
+ either null, or a valid keymap value.lineWrapping (boolean)
false
(scroll).lineNumbers (boolean)
firstLineNumber (integer)
lineNumberFormatter (function(integer))
gutter (boolean)
fixedGutter (boolean)
readOnly (boolean)
"nocursor"
is given (instead of
+ simply true
), focusing of the editor is also
+ disallowed.onChange (function)
{from, to, text, next}
+ object containing information about the changes
+ that occurred as second argument. from
+ and to
are the positions (in the pre-change
+ coordinate system) where the change started and
+ ended (for example, it might be {ch:0, line:18}
if the
+ position is at the beginning of line #19). text
+ is an array of strings representing the text that replaced the changed
+ range (split by line). If multiple changes happened during a single
+ operation, the object will have a next
property pointing to
+ another change object (which may point to another, etc).onCursorActivity (function)
onViewportChange (function)
onGutterClick (function)
mousedown
+ event object as third argument.onFocus, onBlur (function)
onScroll (function)
onUpdate (function)
matchBrackets (boolean)
cursorBlinkRate (number)
workTime, workDelay (number)
workTime
milliseconds, and then use
+ timeout to sleep for workDelay
milliseconds. The
+ defaults are 200 and 300, you can change these options to make
+ the highlighting more or less aggressive.pollInterval (number)
undoDepth (integer)
tabindex (integer)
autofocus (boolean)
fromTextArea
is
+ used, and no explicit value is given for this option, it will be
+ set to true when either the source textarea is focused, or it
+ has an autofocus
attribute and no other element is
+ focused.dragDrop (boolean)
onDragEvent (function)
dragenter
, dragover
,
+ or drop
event. It will be passed the editor instance
+ and the event object as arguments. The callback can choose to
+ handle the event itself, in which case it should
+ return true
to indicate that CodeMirror should not
+ do anything further.onKeyEvent (function)
keydown
, keyup
,
+ and keypress
event that CodeMirror captures. It
+ will be passed two arguments, the editor instance and the key
+ event. This key event is pretty much the raw key event, except
+ that a stop()
method is always added to it. You
+ could feed it to, for example, jQuery.Event
to
+ further normalize it.keydown
does not stop
+ the keypress
from firing, whereas on others it
+ does. If you respond to an event, you should probably inspect
+ its type
property and only do something when it
+ is keydown
(or keypress
for actions
+ that need character data).Keymaps are ways to associate keys with functionality. A keymap + is an object mapping strings that identify the keys to functions + that implement their functionality.
+ +Keys are identified either by name or by character.
+ The CodeMirror.keyNames
object defines names for
+ common keys and associates them with their key codes. Examples of
+ names defined here are Enter
, F5
,
+ and Q
. These can be prefixed
+ with Shift-
, Cmd-
, Ctrl-
,
+ and Alt-
(in that order!) to specify a modifier. So
+ for example, Shift-Ctrl-Space
would be a valid key
+ identifier.
Alternatively, a character can be specified directly by
+ surrounding it in single quotes, for example '$'
+ or 'q'
. Due to limitations in the way browsers fire
+ key events, these may not be prefixed with modifiers.
The CodeMirror.keyMap
object associates keymaps
+ with names. User code and keymap definitions can assign extra
+ properties to this object. Anywhere where a keymap is expected, a
+ string can be given, which will be looked up in this object. It
+ also contains the "default"
keymap holding the
+ default bindings.
The values of properties in keymaps can be either functions of
+ a single argument (the CodeMirror instance), strings, or
+ false
. Such strings refer to properties of the
+ CodeMirror.commands
object, which defines a number of
+ common commands that are used by the default keybindings, and maps
+ them to functions. If the property is set to false
,
+ CodeMirror leaves handling of the key up to the browser. A key
+ handler function may throw CodeMirror.Pass
to indicate
+ that it has decided not to handle the key, and other handlers (or
+ the default behavior) should be given a turn.
Keys mapped to command names that start with the
+ characters "go"
(which should be used for
+ cursor-movement actions) will be fired even when an
+ extra Shift
modifier is present (i.e. "Up":
+ "goLineUp"
matches both up and shift-up). This is used to
+ easily implement shift-selection.
Keymaps can defer to each other by defining
+ a fallthrough
property. This indicates that when a
+ key is not found in the map itself, one or more other maps should
+ be searched. It can hold either a single keymap or an array of
+ keymaps.
When a keymap contains a nofallthrough
property
+ set to true
, keys matched against that map will be
+ ignored if they don't match any of the bindings in the map (no
+ further child maps will be tried, and the default effect of
+ inserting a character will not occur).
Up to a certain extent, CodeMirror's look can be changed by
+ modifying style sheet files. The style sheets supplied by modes
+ simply provide the colors for that mode, and can be adapted in a
+ very straightforward way. To style the editor itself, it is
+ possible to alter or override the styles defined
+ in codemirror.css
.
Some care must be taken there, since a lot of the rules in this + file are necessary to have CodeMirror function properly. Adjusting + colors should be safe, of course, and with some care a lot of + other things can be changed as well. The CSS classes defined in + this file serve the following roles:
+ +CodeMirror
CodeMirror-scroll
overflow: auto
+ fixed height). By
+ default, it does. Giving this height: auto; overflow:
+ visible;
will cause the editor to resize to fit its
+ content.CodeMirror-focused
CodeMirror-gutter
CodeMirror-gutter-text
for that. By default,
+ the gutter is 'fluid', meaning it will adjust its width to the
+ maximum line number or line marker width. You can also set a
+ fixed width if you want.CodeMirror-gutter-text
CodeMirror
class.CodeMirror-lines
CodeMirror-gutter
should have the same
+ padding.CodeMirror-cursor
CodeMirror-selected
span
elements
+ with this class.CodeMirror-matchingbracket
,
+ CodeMirror-nonmatchingbracket
So note carefully that, in order to resize the
+ editor, you should set a width
on
+ the wrapper
+ (class CodeMirror
) element, and a height on
+ the scroller
+ (class CodeMirror-scroll
) element.
The actual lines, as well as the cursor, are represented
+ by pre
elements. By default no text styling (such as
+ bold) that might change line height is applied. If you do want
+ such effects, you'll have to give CodeMirror pre
a
+ fixed height.
If your page's style sheets do funky things to
+ all div
or pre
elements (you probably
+ shouldn't do that), you'll have to define rules to cancel these
+ effects out again for elements under the CodeMirror
+ class.
Themes are also simply CSS files, which define colors for
+ various syntactic elements. See the files in
+ the theme
directory.
A lot of CodeMirror features are only available through its API. + This has the disadvantage that you need to do work to enable them, + and the advantage that CodeMirror will fit seamlessly into your + application.
+ +Whenever points in the document are represented, the API uses
+ objects with line
and ch
properties.
+ Both are zero-based. CodeMirror makes sure to 'clip' any positions
+ passed by client code so that they fit inside the document, so you
+ shouldn't worry too much about sanitizing your coordinates. If you
+ give ch
a value of null
, or don't
+ specify it, it will be replaced with the length of the specified
+ line.
getValue() → string
"\n"
).setValue(string)
getSelection() → string
replaceSelection(string)
setSize(width, height)
width
and height
height
+ can be either numbers (interpreted as pixels) or CSS units
+ ("100%"
, for example). You can
+ pass null
for either of them to indicate that that
+ dimension should not be changed.focus()
scrollTo(x, y)
null
+ or undefined
to have no effect.getScrollInfo()
{x, y, width, height}
object that
+ represents the current scroll position and scrollable area size
+ of the editor.scrollIntoView(pos)
{line, ch}
position into
+ view. If no argument is given, this will scroll the cursor into
+ view.setOption(option, value)
option
+ should the name of an option,
+ and value
should be a valid value for that
+ option.getOption(option) → value
getMode() → object
getOption("mode")
, which gives you
+ the mode specification, rather than the resolved, instantiated
+ mode object.cursorCoords(start, mode) → object
{x, y, yBot}
object containing the
+ coordinates of the cursor. If mode
+ is "local"
, they will be relative to the top-left
+ corner of the editable document. If it is "page"
or
+ not given, they are relative to the top-left corner of the
+ page. yBot
is the coordinate of the bottom of the
+ cursor. start
is a boolean indicating whether you
+ want the start or the end of the selection.charCoords(pos, mode) → object
cursorCoords
, but returns the position of
+ an arbitrary characters. pos
should be
+ a {line, ch}
object.coordsChar(object) → pos
{x, y}
object (in page coordinates),
+ returns the {line, ch}
position that corresponds to
+ it.defaultTextHeight() → number
undo()
redo()
historySize() → object
{undo, redo}
properties,
+ both of which hold integers, indicating the amount of stored
+ undo and redo operations.clearHistory()
getHistory() → object
setHistory(object)
getHistory
. Note that
+ this will have entirely undefined results if the editor content
+ isn't also the same as it was when getHistory
was
+ called.indentLine(line, dir)
dir
is true) or
+ decreased (if false) by an indent
+ unit instead.getTokenAt(pos) → object
{line, ch}
object). The
+ returned object has the following properties:
+ start
end
string
className
state
markText(from, to, className, options) → object
from
and to
should
+ be {line, ch}
objects. The options
+ parameter is optional. When given, it should be an object that
+ may contain the following configuration options:
+ inclusiveLeft
inclusiveRight
inclusiveLeft
,
+ but for the right side.startStyle
endStyle
startStyle
, but for the rightmost span.clear()
, which removes the mark,
+ and find()
, which returns a {from, to}
+ (both document positions), indicating the current position of
+ the marked range, or undefined
if the marker is no
+ longer in the document.setBookmark(pos) → object
find()
and clear()
. The first
+ returns the current position of the bookmark, if it is still in
+ the document, and the second explicitly removes the
+ bookmark.findMarksAt(pos) → array
setMarker(line, text, className) → lineHandle
text
and className
are
+ optional. Setting text
to a Unicode character like
+ ● tends to give a nice effect. To put a picture in the gutter,
+ set text
to a space and className
to
+ something that sets a background image. If you
+ specify text
, the given text (which may contain
+ HTML) will, by default, replace the line number for that line.
+ If this is not what you want, you can include the
+ string %N%
in the text, which will be replaced by
+ the line number.clearMarker(line)
setMarker
. line
can be either a
+ number or a handle returned by setMarker
(since a
+ number may now refer to a different line if something was added
+ or deleted).setLineClass(line, className, backgroundClassName) → lineHandle
line
+ can be a number or a line handle (as returned
+ by setMarker
or this
+ function). className
will be used to style the text
+ for the line, and backgroundClassName
to style its
+ background (which lies behind the selection).
+ Pass null
to clear the classes for a line.hideLine(line) → lineHandle
showLine(line) → lineHandle
hideLine
—re-shows a previously
+ hidden line, by number or by handle.onDeleteLine(line, func)
lineInfo(line) → object
setMarker
. The returned object has the
+ structure {line, handle, text, markerText, markerClass,
+ lineClass, bgClass}
.getLineHandle(num) → lineHandle
getViewport() → object
{from, to}
object indicating the
+ start (inclusive) and end (exclusive) of the currently displayed
+ part of the document. In big documents, when most content is
+ scrolled out of view, CodeMirror will only render the visible
+ part, and a margin around it. See also
+ the onViewportChange
+ option.addWidget(pos, node, scrollIntoView)
node
, which should be an absolutely
+ positioned DOM node, into the editor, positioned right below the
+ given {line, ch}
position.
+ When scrollIntoView
is true, the editor will ensure
+ that the entire node is visible (if possible). To remove the
+ widget again, simply use DOM methods (move it somewhere else, or
+ call removeChild
on its parent).matchBrackets()
lineCount() → number
getCursor(start) → object
start
is a boolean indicating whether the start
+ or the end of the selection must be retrieved. If it is not
+ given, the current cursor pos, i.e. the side of the selection
+ that would move if you pressed an arrow key, is chosen.
+ A {line, ch}
object will be returned.somethingSelected() → boolean
setCursor(pos)
{line, ch}
object, or the line and the
+ character as two separate parameters.setSelection(start, end)
start
+ and end
should be {line, ch}
objects.getLine(n) → string
n
.setLine(n, text)
n
.removeLine(n)
getRange(from, to) → string
+ {line, ch}
objects. An optional third
+ argument can be given to indicate the line separator string to
+ use (defaults to "\n"
).replaceRange(string, from, to)
from
+ and to
with the given string. from
+ and to
must be {line, ch}
+ objects. to
can be left off to simply insert the
+ string at position from
.posFromIndex(index) → object
{line, ch}
object for a
+ zero-based index
who's value is relative to the start of the
+ editor's text. If the index
is out of range of the text then
+ the returned object is clipped to start or end of the text
+ respectively.indexFromPos(object) → number
posFromIndex
.The following are more low-level methods:
+ +operation(func) → result
compoundChange(func) → result
refresh()
getInputField() → textarea
getWrapperElement() → node
width
style when
+ resizing.getScrollerElement() → node
height
style of this element to resize an
+ editor. (You might have to call
+ the refresh
method
+ afterwards.)getGutterElement() → node
getStateAfter(line) → state
The CodeMirror
object itself provides
+ several useful properties. Firstly, its version
+ property contains a string that indicates the version of the
+ library. For releases, this simply
+ contains "major.minor"
(for
+ example "2.33"
. For beta versions, " B"
+ (space, capital B) is added at the end of the string, for
+ development snapshots, " +"
(space, plus) is
+ added.
The CodeMirror.fromTextArea
+ method provides another way to initialize an editor. It takes a
+ textarea DOM node as first argument and an optional configuration
+ object as second. It will replace the textarea with a CodeMirror
+ instance, and wire up the form of that textarea (if any) to make
+ sure the editor contents are put into the textarea when the form
+ is submitted. A CodeMirror instance created this way has three
+ additional methods:
save()
toTextArea()
getTextArea() → textarea
If you want to define extra methods in terms
+ of the CodeMirror API, it is possible to
+ use CodeMirror.defineExtension(name, value)
. This
+ will cause the given value (usually a method) to be added to all
+ CodeMirror instances created from then on.
If your extention just needs to run some
+ code whenever a CodeMirror instance is initialized,
+ use CodeMirror.defineInitHook
. Give it a function as
+ its only argument, and from then on, that function will be called
+ (with the instance as argument) whenever a new CodeMirror instance
+ is initialized.
The lib/util
directory in the distribution
+ contains a number of reusable components that implement extra
+ editor functionality. In brief, they are:
dialog.js
openDialog
method to CodeMirror instances,
+ which can be called with an HTML fragment that provides the
+ prompt (should include an input
tag), and a
+ callback function that is called when text has been entered.
+ Depends on lib/util/dialog.css
.searchcursor.js
getSearchCursor(query, start, caseFold) →
+ cursor
method to CodeMirror instances, which can be used
+ to implement search/replace functionality. query
+ can be a regular expression or a string (only strings will match
+ across lines—if they contain newlines). start
+ provides the starting position of the search. It can be
+ a {line, ch}
object, or can be left off to default
+ to the start of the document. caseFold
is only
+ relevant when matching a string. It will cause the search to be
+ case-insensitive. A search cursor has the following methods:
+ findNext(), findPrevious() → boolean
match
method, in case you
+ want to extract matched groups.from(), to() → object
findNext
or findPrevious
did
+ not return false. They will return {line, ch}
+ objects pointing at the start and end of the match.replace(text)
search.js
searchcursor.js
, and will make use
+ of openDialog
when
+ available to make prompting for search queries less ugly.foldcode.js
CodeMirror.newFoldFunction
with a range-finder
+ helper function to create a function that will, when applied to
+ a CodeMirror instance and a line number, attempt to fold or
+ unfold the block starting at the given line. A range-finder is a
+ language-specific function that also takes an instance and a
+ line number, and returns an end line for the block, or null if
+ no block is started on that line. This file
+ provides CodeMirror.braceRangeFinder
, which finds
+ blocks in brace languages (JavaScript, C, Java,
+ etc), CodeMirror.indentRangeFinder
, for languages
+ where indentation determines block structure (Python, Haskell),
+ and CodeMirror.tagRangeFinder
, for XML-style
+ languages.runmode.js
overlay.js
CodeMirror.overlayMode
, which is used to
+ create such a mode. See this
+ demo for a detailed example.multiplex.js
CodeMirror.multiplexingMode
which, when
+ given as first argument a mode object, and as other arguments
+ any number of {open, close, mode [, delimStyle]}
+ objects, will return a mode object that starts parsing using the
+ mode passed as first argument, but will switch to another mode
+ as soon as it encounters a string that occurs in one of
+ the open
fields of the passed objects. When in a
+ sub-mode, it will go back to the top mode again when
+ the close
string is encountered.
+ When delimStyle
is specified, it will be the token
+ style returned for the delimiter tokens. The outer mode will not
+ see the content between the delimiters.
+ See this demo for an
+ example.simple-hint.js
CodeMirror.simpleHint
, which takes a
+ CodeMirror instance and a hinting function, and pops up a widget
+ that allows the user to select a completion. Hinting functions
+ are function that take an editor instance, and return
+ a {list, from, to}
object, where list
+ is an array of strings (the completions), and from
+ and to
give the start and end of the token that is
+ being completed. Depends
+ on lib/util/simple-hint.css
.javascript-hint.js
CodeMirror.javascriptHint
+ and CodeMirror.coffeescriptHint
, which are simple
+ hinting functions for the JavaScript and CoffeeScript
+ modes.match-highlighter.js
matchHighlight
method to CodeMirror
+ instances that can be called (typically from
+ a onCursorActivity
+ handler) to highlight all instances of a currently selected word
+ with the a classname given as a first argument to the method.
+ Depends on
+ the searchcursor
+ add-on. Demo here.formatting.js
commentRange
, autoIndentRange
,
+ and autoFormatRange
methods that, respectively,
+ comment (or uncomment), indent, or format (add line breaks) a
+ range of code. Demo here.closetag.js
loadmode.js
CodeMirror.requireMode(modename,
+ callback)
function that will try to load a given mode and
+ call the callback when it succeeded. You'll have to
+ set CodeMirror.modeURL
to a string that mode paths
+ can be constructed from, for
+ example "mode/%N/%N.js"
—the %N
's will
+ be replaced with the mode name. Also
+ defines CodeMirror.autoLoadMode(instance, mode)
,
+ which will ensure the given mode is loaded and cause the given
+ editor instance to refresh its mode when the loading
+ succeeded. See the demo.continuecomment.js
newlineAndIndentContinueComment
that you can
+ bind Enter
to in order to have the editor prefix
+ new lines inside C-like block comments with an asterisk.Modes typically consist of a single JavaScript file. This file + defines, in the simplest case, a lexer (tokenizer) for your + language—a function that takes a character stream as input, + advances it past a token, and returns a style for that token. More + advanced modes can also handle indentation for the language.
+ +The mode script should
+ call CodeMirror.defineMode
to register itself with
+ CodeMirror. This function takes two arguments. The first should be
+ the name of the mode, for which you should use a lowercase string,
+ preferably one that is also the name of the files that define the
+ mode (i.e. "xml"
is defined xml.js
). The
+ second argument should be a function that, given a CodeMirror
+ configuration object (the thing passed to
+ the CodeMirror
function) and an optional mode
+ configuration object (as in
+ the mode
option), returns
+ a mode object.
Typically, you should use this second argument
+ to defineMode
as your module scope function (modes
+ should not leak anything into the global scope!), i.e. write your
+ whole mode inside this function.
The main responsibility of a mode script is parsing + the content of the editor. Depending on the language and the + amount of functionality desired, this can be done in really easy + or extremely complicated ways. Some parsers can be stateless, + meaning that they look at one element (token) of the code + at a time, with no memory of what came before. Most, however, will + need to remember something. This is done by using a state + object, which is an object that is always passed when + reading a token, and which can be mutated by the tokenizer.
+ +Modes that use a state must define
+ a startState
method on their mode object. This is a
+ function of no arguments that produces a state object to be used
+ at the start of a document.
The most important part of a mode object is
+ its token(stream, state)
method. All modes must
+ define this method. It should read one token from the stream it is
+ given as an argument, optionally update its state, and return a
+ style string, or null
for tokens that do not have to
+ be styled. For your styles, you can either use the 'standard' ones
+ defined in the themes (without the cm-
prefix), or
+ define your own and have people include a custom CSS file for your
+ mode.
+ +
The stream object encapsulates a line of code + (tokens may never span lines) and our current position in that + line. It has the following API:
+ +eol() → boolean
sol() → boolean
peek() → character
next() → character
undefined
when no more characters are
+ available.eat(match) → character
match
can be a character, a regular expression,
+ or a function that takes a character and returns a boolean. If
+ the next character in the stream 'matches' the given argument,
+ it is consumed and returned. Otherwise, undefined
+ is returned.eatWhile(match) → boolean
eat
with the given argument,
+ until it fails. Returns true if any characters were eaten.eatSpace() → boolean
eatWhile
when matching
+ white-space.skipToEnd()
skipTo(ch) → boolean
match(pattern, consume, caseFold) → boolean
eat
—if consume
is true
+ or not given—or a look-ahead that doesn't update the stream
+ position—if it is false. pattern
can be either a
+ string or a regular expression starting with ^
.
+ When it is a string, caseFold
can be set to true to
+ make the match case-insensitive. When successfully matching a
+ regular expression, the returned value will be the array
+ returned by match
, in case you need to extract
+ matched groups.backUp(n)
n
characters. Backing it up
+ further than the start of the current token will cause things to
+ break, so be careful.column() → integer
indentation() → integer
current() → string
By default, blank lines are simply skipped when
+ tokenizing a document. For languages that have significant blank
+ lines, you can define a blankLine(state)
method on
+ your mode that will get called whenever a blank line is passed
+ over, so that it can update the parser state.
Because state object are mutated, and CodeMirror
+ needs to keep valid versions of a state around so that it can
+ restart a parse at any line, copies must be made of state objects.
+ The default algorithm used is that a new state object is created,
+ which gets all the properties of the old object. Any properties
+ which hold arrays get a copy of these arrays (since arrays tend to
+ be used as mutable stacks). When this is not correct, for example
+ because a mode mutates non-array properties of its state object, a
+ mode object should define a copyState
method,
+ which is given a state and should return a safe copy of that
+ state.
If you want your mode to provide smart indentation
+ (through the indentLine
+ method and the indentAuto
+ and newlineAndIndent
commands, which keys can be
+ bound to), you must define
+ an indent(state, textAfter)
method on your mode
+ object.
The indentation method should inspect the given state object,
+ and optionally the textAfter
string, which contains
+ the text on the line that is being indented, and return an
+ integer, the amount of spaces to indent. It should usually take
+ the indentUnit
+ option into account.
Finally, a mode may define
+ an electricChars
property, which should hold a string
+ containing all the characters that should trigger the behaviour
+ described for
+ the electricChars
+ option.
So, to summarize, a mode must provide
+ a token
method, and it may
+ provide startState
, copyState
,
+ compareStates
, and indent
methods. For
+ an example of a trivial mode, see
+ the diff mode, for a more involved
+ example, see the C-like
+ mode.
Sometimes, it is useful for modes to nest—to have one
+ mode delegate work to another mode. An example of this kind of
+ mode is the mixed-mode HTML
+ mode. To implement such nesting, it is usually necessary to
+ create mode objects and copy states yourself. To create a mode
+ object, there are CodeMirror.getMode(options,
+ parserConfig)
, where the first argument is a configuration
+ object as passed to the mode constructor function, and the second
+ argument is a mode specification as in
+ the mode
option. To copy a
+ state object, call CodeMirror.copyState(mode, state)
,
+ where mode
is the mode that created the given
+ state.
In a nested mode, it is recommended to add an
+ extra methods, innerMode
which, given a state object,
+ returns a {state, mode}
object with the inner mode
+ and its state for the current position. These are used by utility
+ scripts such as the autoformatter
+ and the tag closer to get context
+ information. Use the CodeMirror.innerMode
helper
+ function to, starting from a mode and a state, recursively walk
+ down to the innermost mode and state.
To make indentation work properly in a nested parser, it is
+ advisable to give the startState
method of modes that
+ are intended to be nested an optional argument that provides the
+ base indentation for the block of code. The JavaScript and CSS
+ parser do this, for example, to allow JavaScript and CSS code
+ inside the mixed-mode HTML mode to be properly indented.
Finally, it is possible to associate your mode, or a certain
+ configuration of your mode, with
+ a MIME type. For
+ example, the JavaScript mode associates itself
+ with text/javascript
, and its JSON variant
+ with application/json
. To do this,
+ call CodeMirror.defineMIME(mime, modeSpec)
,
+ where modeSpec
can be a string or object specifying a
+ mode, as in the mode
+ option.
Sometimes, it is useful to add or override mode
+ object properties from external code.
+ The CodeMirror.extendMode
can be used to add
+ properties to mode objects produced for a specific mode. Its first
+ argument is the name of the mode, its second an object that
+ specifies the properties that should be added. This is mostly
+ useful to add utilities that can later be looked
+ up getMode
.
+/* Old release + history */ ++
27-02-2012: Version 2.22:
+ +autoClearEmptyLines
option.27-01-2012: Version 2.21:
+ +smartIndent
+ option.readOnly
-mode.scrollTo
method.20-12-2011: Version 2.2:
+ +coordsFromIndex
+ to posFromIndex
,
+ add indexFromPos
+ method.21-11-2011: Version 2.18:
+Fixes TextMarker.clear
, which is broken in 2.17.
21-11-2011: Version 2.17:
+setBookmark
method.lib/util
.27-10-2011: Version 2.16:
+coordsFromIndex
method.setValue
now no longer clears history. Use clearHistory
for that.markText
now
+ returns an object with clear
and find
+ methods. Marked text is now more robust when edited.26-09-2011: Version 2.15:
+Fix bug that snuck into 2.14: Clicking the + character that currently has the cursor didn't re-focus the + editor.
+ +26-09-2011: Version 2.14:
+fixedGutter
option.setValue
breaking cursor movement.23-08-2011: Version 2.13:
+getGutterElement
to API.smartHome
option.25-07-2011: Version 2.12:
+innerHTML
for HTML-escaping.04-07-2011: Version 2.11:
+replace
method to search cursors, for cursor-preserving replacements.getStateAfter
API and compareState
mode API methods for finer-grained mode magic.getScrollerElement
API method to manipulate the scrolling DIV.07-06-2011: Version 2.1:
+Add + a theme system + (demo). Note that this is not + backwards-compatible—you'll have to update your styles and + modes!
+ +07-06-2011: Version 2.02:
+26-05-2011: Version 2.01:
+coordsChar
now worksonCursorActivity
interfered with onChange
.onChange
."nocursor"
mode for readOnly
option.onHighlightComplete
option.28-03-2011: Version 2.0:
+CodeMirror 2 is a complete rewrite that's + faster, smaller, simpler to use, and less dependent on browser + quirks. See this + and this + for more information. + +
28-03-2011: Version 1.0:
+22-02-2011: Version 2.0 beta 2:
+Somewhat more mature API, lots of bugs shaken out. + +
17-02-2011: Version 0.94:
+tabMode: "spaces"
was modified slightly (now indents when something is selected).08-02-2011: Version 2.0 beta 1:
+CodeMirror 2 is a complete rewrite of + CodeMirror, no longer depending on an editable frame.
+ +19-01-2011: Version 0.93:
+save
method to instances created with fromTextArea
.17-12-2010: Version 0.92:
+styleNumbers
option is now officially
+ supported and documented.onLineNumberClick
option added.onLoad
and
+ onCursorActivity
callbacks. Old names still work, but
+ are deprecated.11-11-2010: Version 0.91:
+toTextArea
to update the code in the textarea.noScriptCaching
option (hack to ease development).02-10-2010: Version 0.9:
+height: "dynamic"
more robust.enterMode
and electricChars
options to make indentation even more customizable.firstLineNumber
option.@media
rules by the CSS parser.22-07-2010: Version 0.8:
+cursorCoords
method to find the screen
+ coordinates of the cursor.height: dynamic
mode, where the editor's
+ height will adjust to the size of its content.toTextArea
method in instances created with
+ fromTextArea
.27-04-2010: Version + 0.67:
+More consistent page-up/page-down behaviour
+ across browsers. Fix some issues with hidden editors looping forever
+ when line-numbers were enabled. Make PHP parser parse
+ "\\"
correctly. Have jumpToLine
work on
+ line handles, and add cursorLine
function to fetch the
+ line handle where the cursor currently is. Add new
+ setStylesheet
function to switch style-sheets in a
+ running editor.
01-03-2010: Version + 0.66:
+Adds removeLine
method to API.
+ Introduces the PLSQL parser.
+ Marks XML errors by adding (rather than replacing) a CSS class, so
+ that they can be disabled by modifying their style. Fixes several
+ selection bugs, and a number of small glitches.
12-11-2009: Version + 0.65:
+Add support for having both line-wrapping and
+ line-numbers turned on, make paren-highlighting style customisable
+ (markParen
and unmarkParen
config
+ options), work around a selection bug that Opera
+ reintroduced in version 10.
23-10-2009: Version + 0.64:
+Solves some issues introduced by the
+ paste-handling changes from the previous release. Adds
+ setSpellcheck
, setTextWrapping
,
+ setIndentUnit
, setUndoDepth
,
+ setTabMode
, and setLineNumbers
to
+ customise a running editor. Introduces an SQL parser. Fixes a few small
+ problems in the Python
+ parser. And, as usual, add workarounds for various newly discovered
+ browser incompatibilities.
31-08-2009: Version +0.63:
+Overhaul of paste-handling (less fragile), fixes for several +serious IE8 issues (cursor jumping, end-of-document bugs) and a number +of small problems.
+ +30-05-2009: Version +0.62:
+Introduces Python
+and Lua parsers. Add
+setParser
(on-the-fly mode changing) and
+clearHistory
methods. Make parsing passes time-based
+instead of lines-based (see the passTime
option).
+/* Real world uses, + full list */ ++
Contact me if you'd like + your project to be added to this list.
+ ++/* Reporting bugs + effectively */ ++
So you found a problem in CodeMirror. By all means, report it! Bug +reports from users are the main drive behind improvements to +CodeMirror. But first, please read over these points:
+ ++/* Upgrading to + v2.2 */ ++
There are a few things in the 2.2 release that require some care +when upgrading.
+ +The default theme is now included
+in codemirror.css
, so
+you do not have to included it separately anymore. (It was tiny, so
+even if you're not using it, the extra data overhead is negligible.)
+
+
CodeMirror has moved to a system +where keymaps are used to +bind behavior to keys. This means custom +bindings are now possible.
+ +Three options that influenced key
+behavior, tabMode
, enterMode
,
+and smartHome
, are no longer supported. Instead, you can
+provide custom bindings to influence the way these keys act. This is
+done through the
+new extraKeys
+option, which can hold an object mapping key names to functionality. A
+simple example would be:
extraKeys: { + "Ctrl-S": function(instance) { saveText(instance.getValue()); }, + "Ctrl-/": "undo" + }+ +
Keys can be mapped either to functions, which will be given the
+editor instance as argument, or to strings, which are mapped through
+functions through the CodeMirror.commands
table, which
+contains all the built-in editing commands, and can be inspected and
+extended by external code.
By default, the Home
key is bound to
+the "goLineStartSmart"
command, which moves the cursor to
+the first non-whitespace character on the line. You can set do this to
+make it always go to the very start instead:
extraKeys: {"Home": "goLineStart"}+ +
Similarly, Enter
is bound
+to "newlineAndIndent"
by default. You can bind it to
+something else to get different behavior. To disable special handling
+completely and only get a newline character inserted, you can bind it
+to false
:
extraKeys: {"Enter": false}+ +
The same works for Tab
. If you don't want CodeMirror
+to handle it, bind it to false
. The default behaviour is
+to indent the current line more ("indentMore"
command),
+and indent it less when shift is held ("indentLess"
).
+There are also "indentAuto"
(smart indent)
+and "insertTab"
commands provided for alternate
+behaviors. Or you can write your own handler function to do something
+different altogether.
Handling of tabs changed completely. The display width of tabs can
+now be set with the tabSize
option, and tabs can
+be styled by setting CSS rules
+for the cm-tab
class.
The default width for tabs is now 4, as opposed to the 8 that is
+hard-wired into browsers. If you are relying on 8-space tabs, make
+sure you explicitly set tabSize: 8
in your options.
+/* In-browser code editing + made bearable */ ++
CodeMirror is a JavaScript component that + provides a code editor in the browser. When a mode is available for + the language you are coding in, it will color your code, and + optionally help with indentation.
+ +A rich programming API and a CSS + theming system are available for customizing CodeMirror to fit your + application, and extending it with new functionality.
+ +All of CodeMirror is released under a MIT-style license. To get it, you can download + the latest + release or the current development + snapshot as zip files. To create a custom minified script file, + you can use the compression API.
+ +We use git for version control. + The main repository can be fetched in this way:
+ +git clone http://marijnhaverbeke.nl/git/codemirror+ +
CodeMirror can also be found on GitHub at marijnh/CodeMirror. + If you plan to hack on the code and contribute patches, the best way + to do it is to create a GitHub fork, and send pull requests.
+ +The manual is your first stop for + learning how to use this library. It starts with a quick explanation + of how to use the editor, and then describes the API in detail.
+ +For those who want to learn more about the code, there is + an overview of the internals available. + The source code + itself is, for the most part, also well commented.
+ +Community discussion, questions, and informal bug reporting is + done on + the CodeMirror + Google group. There is a separate + group, CodeMirror-announce, + which is lower-volume, and is only used for major announcements—new + versions and such. These will be cross-posted to both groups, so you + don't need to subscribe to both.
+ +Though bug reports through e-mail are responded to, the preferred + way to report bugs is to use + the GitHub + issue tracker. Before reporting a + bug, read these pointers. Also, + the issue tracker is for bugs, not requests for help.
+ +When none of these seem fitting, you can + simply e-mail the maintainer + directly.
+ +The following desktop browsers are able to run CodeMirror:
+ +<!doctype
+ html>
is recommended.)I am not actively testing against every new browser release, and + vendors have a habit of introducing bugs all the time, so I am + relying on the community to tell me when something breaks. + See here for information on how to contact + me.
+ +Mobile browsers mostly kind of work, but, because of limitations + and their fundamentally different UI assumptions, show a lot of + quirks that are hard to work around.
+ +CodeMirror is developed and maintained by me, Marijn Haverbeke, + in my own time. If your company is getting value out of CodeMirror, + please consider purchasing a support contract.
+ +CodeMirror support contracts exist in two + forms—basic at €100 per month, + and premium at €500 per + month. Contact me for further + information.
+ +20-11-2012: Version 2.36:
+ +scrollIntoView
public.defaultTextHeight
method.20-11-2012: Version 3.0, release candidate 1:
+ +New major version. Only partially + backwards-compatible. See + the upgrading + guide for more information. Changes since beta 2:
+ +addLineClass
+ and removeLineClass
,
+ drop setLineClass
.isClean
/markClean
methods.compoundChange
method, use better undo-event-combining heuristic.22-10-2012: Version 2.35:
+ +markText
/undo interaction.defineInitHook
function.22-10-2012: Version 3.0, beta 2:
+ +gutterClick
event.cursorHeight
option.viewportMargin
option.flattenSpans
option.19-09-2012: Version 2.34:
+ +compareStates
is no longer needed.onHighlightComplete
no longer works.CodeMirror.version
property.19-09-2012: Version 3.0, beta 1:
+ +23-08-2012: Version 2.33:
+ +getViewPort
and onViewportChange
API.false
disabling handling (again).innerHTML
. Remove CodeMirror.htmlEscape
.23-07-2012: Version 2.32:
+ +Emergency fix for a bug where an editor with + line wrapping on IE will break when there is no + scrollbar.
+ +20-07-2012: Version 2.31:
+ +setSize
method for programmatic resizing.getHistory
and setHistory
methods.getValue
and getRange
.22-06-2012: Version 2.3:
+ +getScrollInfo
method.23-05-2012: Version 2.25:
+ +23-04-2012: Version 2.24:
+ +dragDrop
+ and onDragEvent
+ options.compoundChange
API method.catchall
in key maps,
+ add nofallthrough
boolean field instead.26-03-2012: Version 2.23:
+ +setLineClass
.charCoords
+ and cursorCoords
with a mode
argument.autofocus
option.findMarksAt
method.Simple mode that tries to handle C-like languages as well as it
+ can. Takes two configuration parameters: keywords
, an
+ object whose property names are the keywords in the language,
+ and useCPP
, which determines whether C preprocessor
+ directives are recognized.
MIME types defined: text/x-csrc
+ (C code), text/x-c++src
(C++
+ code), text/x-java
(Java
+ code), text/x-csharp
(C#).
MIME types defined: text/x-clojure
.
MIME types defined: text/x-coffeescript
.
The CoffeeScript mode was written by Jeff Pickhardt (license).
+ + + diff --git a/codemirror-2.36/mode/commonlisp/commonlisp.js b/codemirror-2.36/mode/commonlisp/commonlisp.js new file mode 100644 index 00000000..4fb4bdf9 --- /dev/null +++ b/codemirror-2.36/mode/commonlisp/commonlisp.js @@ -0,0 +1,101 @@ +CodeMirror.defineMode("commonlisp", function (config) { + var assumeBody = /^with|^def|^do|^prog|case$|^cond$|bind$|when$|unless$/; + var numLiteral = /^(?:[+\-]?(?:\d+|\d*\.\d+)(?:[efd][+\-]?\d+)?|[+\-]?\d+(?:\/[+\-]?\d+)?|#b[+\-]?[01]+|#o[+\-]?[0-7]+|#x[+\-]?[\da-f]+)/; + var symbol = /[^\s'`,@()\[\]";]/; + var type; + + function readSym(stream) { + var ch; + while (ch = stream.next()) { + if (ch == "\\") stream.next(); + else if (!symbol.test(ch)) { stream.backUp(1); break; } + } + return stream.current(); + } + + function base(stream, state) { + if (stream.eatSpace()) {type = "ws"; return null;} + if (stream.match(numLiteral)) return "number"; + var ch = stream.next(); + if (ch == "\\") ch = stream.next(); + + if (ch == '"') return (state.tokenize = inString)(stream, state); + else if (ch == "(") { type = "open"; return "bracket"; } + else if (ch == ")" || ch == "]") { type = "close"; return "bracket"; } + else if (ch == ";") { stream.skipToEnd(); type = "ws"; return "comment"; } + else if (/['`,@]/.test(ch)) return null; + else if (ch == "|") { + if (stream.skipTo("|")) { stream.next(); return "symbol"; } + else { stream.skipToEnd(); return "error"; } + } else if (ch == "#") { + var ch = stream.next(); + if (ch == "[") { type = "open"; return "bracket"; } + else if (/[+\-=\.']/.test(ch)) return null; + else if (/\d/.test(ch) && stream.match(/^\d*#/)) return null; + else if (ch == "|") return (state.tokenize = inComment)(stream, state); + else if (ch == ":") { readSym(stream); return "meta"; } + else return "error"; + } else { + var name = readSym(stream); + if (name == ".") return null; + type = "symbol"; + if (name == "nil" || name == "t") return "atom"; + if (name.charAt(0) == ":") return "keyword"; + if (name.charAt(0) == "&") return "variable-2"; + return "variable"; + } + } + + function inString(stream, state) { + var escaped = false, next; + while (next = stream.next()) { + if (next == '"' && !escaped) { state.tokenize = base; break; } + escaped = !escaped && next == "\\"; + } + return "string"; + } + + function inComment(stream, state) { + var next, last; + while (next = stream.next()) { + if (next == "#" && last == "|") { state.tokenize = base; break; } + last = next; + } + type = "ws"; + return "comment"; + } + + return { + startState: function () { + return {ctx: {prev: null, start: 0, indentTo: 0}, tokenize: base}; + }, + + token: function (stream, state) { + if (stream.sol() && typeof state.ctx.indentTo != "number") + state.ctx.indentTo = state.ctx.start + 1; + + type = null; + var style = state.tokenize(stream, state); + if (type != "ws") { + if (state.ctx.indentTo == null) { + if (type == "symbol" && assumeBody.test(stream.current())) + state.ctx.indentTo = state.ctx.start + config.indentUnit; + else + state.ctx.indentTo = "next"; + } else if (state.ctx.indentTo == "next") { + state.ctx.indentTo = stream.column(); + } + } + if (type == "open") state.ctx = {prev: state.ctx, start: stream.column(), indentTo: null}; + else if (type == "close") state.ctx = state.ctx.prev || state.ctx; + return style; + }, + + indent: function (state, textAfter) { + var i = state.ctx.indentTo; + return typeof i == "number" ? i : state.ctx.start + 1; + } + }; +}); + +CodeMirror.defineMIME("text/x-common-lisp", "commonlisp"); diff --git a/codemirror-2.36/mode/commonlisp/index.html b/codemirror-2.36/mode/commonlisp/index.html new file mode 100644 index 00000000..f9766a84 --- /dev/null +++ b/codemirror-2.36/mode/commonlisp/index.html @@ -0,0 +1,165 @@ + + + + +MIME types defined: text/x-common-lisp
.
MIME types defined: text/css
.
Parsing/Highlighting Tests: normal, verbose.
+ + + diff --git a/codemirror-2.36/mode/css/test.js b/codemirror-2.36/mode/css/test.js new file mode 100644 index 00000000..fd6a4b8a --- /dev/null +++ b/codemirror-2.36/mode/css/test.js @@ -0,0 +1,501 @@ +// Initiate ModeTest and set defaults +var MT = ModeTest; +MT.modeName = 'css'; +MT.modeOptions = {}; + +// Requires at least one media query +MT.testMode( + 'atMediaEmpty', + '@media { }', + [ + 'def', '@media', + null, ' ', + 'error', '{', + null, ' }' + ] +); + +MT.testMode( + 'atMediaMultiple', + '@media not screen and (color), not print and (color) { }', + [ + 'def', '@media', + null, ' ', + 'keyword', 'not', + null, ' ', + 'attribute', 'screen', + null, ' ', + 'operator', 'and', + null, ' (', + 'property', 'color', + null, '), ', + 'keyword', 'not', + null, ' ', + 'attribute', 'print', + null, ' ', + 'operator', 'and', + null, ' (', + 'property', 'color', + null, ') { }' + ] +); + +MT.testMode( + 'atMediaCheckStack', + '@media screen { } foo { }', + [ + 'def', '@media', + null, ' ', + 'attribute', 'screen', + null, ' { } ', + 'tag', 'foo', + null, ' { }' + ] +); + +MT.testMode( + 'atMediaCheckStack', + '@media screen (color) { } foo { }', + [ + 'def', '@media', + null, ' ', + 'attribute', 'screen', + null, ' (', + 'property', 'color', + null, ') { } ', + 'tag', 'foo', + null, ' { }' + ] +); + +MT.testMode( + 'atMediaCheckStackInvalidAttribute', + '@media foobarhello { } foo { }', + [ + 'def', '@media', + null, ' ', + 'attribute error', 'foobarhello', + null, ' { } ', + 'tag', 'foo', + null, ' { }' + ] +); + +// Error, because "and" is only allowed immediately preceding a media expression +MT.testMode( + 'atMediaInvalidAttribute', + '@media foobarhello { }', + [ + 'def', '@media', + null, ' ', + 'attribute error', 'foobarhello', + null, ' { }' + ] +); + +// Error, because "and" is only allowed immediately preceding a media expression +MT.testMode( + 'atMediaInvalidAnd', + '@media and screen { }', + [ + 'def', '@media', + null, ' ', + 'error', 'and', + null, ' ', + 'attribute', 'screen', + null, ' { }' + ] +); + +// Error, because "not" is only allowed as the first item in each media query +MT.testMode( + 'atMediaInvalidNot', + '@media screen not (not) { }', + [ + 'def', '@media', + null, ' ', + 'attribute', 'screen', + null, ' ', + 'error', 'not', + null, ' (', + 'error', 'not', + null, ') { }' + ] +); + +// Error, because "only" is only allowed as the first item in each media query +MT.testMode( + 'atMediaInvalidOnly', + '@media screen only (only) { }', + [ + 'def', '@media', + null, ' ', + 'attribute', 'screen', + null, ' ', + 'error', 'only', + null, ' (', + 'error', 'only', + null, ') { }' + ] +); + +// Error, because "foobarhello" is neither a known type or property, but +// property was expected (after "and"), and it should be in parenthese. +MT.testMode( + 'atMediaUnknownType', + '@media screen and foobarhello { }', + [ + 'def', '@media', + null, ' ', + 'attribute', 'screen', + null, ' ', + 'operator', 'and', + null, ' ', + 'error', 'foobarhello', + null, ' { }' + ] +); + +// Error, because "color" is not a known type, but is a known property, and +// should be in parentheses. +MT.testMode( + 'atMediaInvalidType', + '@media screen and color { }', + [ + 'def', '@media', + null, ' ', + 'attribute', 'screen', + null, ' ', + 'operator', 'and', + null, ' ', + 'error', 'color', + null, ' { }' + ] +); + +// Error, because "print" is not a known property, but is a known type, +// and should not be in parenthese. +MT.testMode( + 'atMediaInvalidProperty', + '@media screen and (print) { }', + [ + 'def', '@media', + null, ' ', + 'attribute', 'screen', + null, ' ', + 'operator', 'and', + null, ' (', + 'error', 'print', + null, ') { }' + ] +); + +// Soft error, because "foobarhello" is not a known property or type. +MT.testMode( + 'atMediaUnknownProperty', + '@media screen and (foobarhello) { }', + [ + 'def', '@media', + null, ' ', + 'attribute', 'screen', + null, ' ', + 'operator', 'and', + null, ' (', + 'property error', 'foobarhello', + null, ') { }' + ] +); + +MT.testMode( + 'tagSelector', + 'foo { }', + [ + 'tag', 'foo', + null, ' { }' + ] +); + +MT.testMode( + 'classSelector', + '.foo-bar_hello { }', + [ + 'qualifier', '.foo-bar_hello', + null, ' { }' + ] +); + +MT.testMode( + 'idSelector', + '#foo { #foo }', + [ + 'builtin', '#foo', + null, ' { ', + 'error', '#foo', + null, ' }' + ] +); + +MT.testMode( + 'tagSelectorUnclosed', + 'foo { margin: 0 } bar { }', + [ + 'tag', 'foo', + null, ' { ', + 'property', 'margin', + 'operator', ':', + null, ' ', + 'number', '0', + null, ' } ', + 'tag', 'bar', + null, ' { }' + ] +); + +MT.testMode( + 'tagStringNoQuotes', + 'foo { font-family: hello world; }', + [ + 'tag', 'foo', + null, ' { ', + 'property', 'font-family', + 'operator', ':', + null, ' ', + 'variable-2', 'hello', + null, ' ', + 'variable-2', 'world', + null, '; }' + ] +); + +MT.testMode( + 'tagStringDouble', + 'foo { font-family: "hello world"; }', + [ + 'tag', 'foo', + null, ' { ', + 'property', 'font-family', + 'operator', ':', + null, ' ', + 'string', '"hello world"', + null, '; }' + ] +); + +MT.testMode( + 'tagStringSingle', + 'foo { font-family: \'hello world\'; }', + [ + 'tag', 'foo', + null, ' { ', + 'property', 'font-family', + 'operator', ':', + null, ' ', + 'string', '\'hello world\'', + null, '; }' + ] +); + +MT.testMode( + 'tagColorKeyword', + 'foo { color: black; }', + [ + 'tag', 'foo', + null, ' { ', + 'property', 'color', + 'operator', ':', + null, ' ', + 'keyword', 'black', + null, '; }' + ] +); + +MT.testMode( + 'tagColorHex3', + 'foo { background: #fff; }', + [ + 'tag', 'foo', + null, ' { ', + 'property', 'background', + 'operator', ':', + null, ' ', + 'atom', '#fff', + null, '; }' + ] +); + +MT.testMode( + 'tagColorHex6', + 'foo { background: #ffffff; }', + [ + 'tag', 'foo', + null, ' { ', + 'property', 'background', + 'operator', ':', + null, ' ', + 'atom', '#ffffff', + null, '; }' + ] +); + +MT.testMode( + 'tagColorHex4', + 'foo { background: #ffff; }', + [ + 'tag', 'foo', + null, ' { ', + 'property', 'background', + 'operator', ':', + null, ' ', + 'atom error', '#ffff', + null, '; }' + ] +); + +MT.testMode( + 'tagColorHexInvalid', + 'foo { background: #ffg; }', + [ + 'tag', 'foo', + null, ' { ', + 'property', 'background', + 'operator', ':', + null, ' ', + 'atom error', '#ffg', + null, '; }' + ] +); + +MT.testMode( + 'tagNegativeNumber', + 'foo { margin: -5px; }', + [ + 'tag', 'foo', + null, ' { ', + 'property', 'margin', + 'operator', ':', + null, ' ', + 'number', '-5px', + null, '; }' + ] +); + +MT.testMode( + 'tagPositiveNumber', + 'foo { padding: 5px; }', + [ + 'tag', 'foo', + null, ' { ', + 'property', 'padding', + 'operator', ':', + null, ' ', + 'number', '5px', + null, '; }' + ] +); + +MT.testMode( + 'tagVendor', + 'foo { -foo-box-sizing: -foo-border-box; }', + [ + 'tag', 'foo', + null, ' { ', + 'meta', '-foo-', + 'property', 'box-sizing', + 'operator', ':', + null, ' ', + 'meta', '-foo-', + 'string-2', 'border-box', + null, '; }' + ] +); + +MT.testMode( + 'tagBogusProperty', + 'foo { barhelloworld: 0; }', + [ + 'tag', 'foo', + null, ' { ', + 'property error', 'barhelloworld', + 'operator', ':', + null, ' ', + 'number', '0', + null, '; }' + ] +); + +MT.testMode( + 'tagTwoProperties', + 'foo { margin: 0; padding: 0; }', + [ + 'tag', 'foo', + null, ' { ', + 'property', 'margin', + 'operator', ':', + null, ' ', + 'number', '0', + null, '; ', + 'property', 'padding', + 'operator', ':', + null, ' ', + 'number', '0', + null, '; }' + ] +); +// +//MT.testMode( +// 'tagClass', +// '@media only screen and (min-width: 500px), print {foo.bar#hello { color: black !important; background: #f00; margin: -5px; padding: 5px; -foo-box-sizing: border-box; } /* world */}', +// [ +// 'def', '@media', +// null, ' ', +// 'keyword', 'only', +// null, ' ', +// 'attribute', 'screen', +// null, ' ', +// 'operator', 'and', +// null, ' ', +// 'bracket', '(', +// 'property', 'min-width', +// 'operator', ':', +// null, ' ', +// 'number', '500px', +// 'bracket', ')', +// null, ', ', +// 'attribute', 'print', +// null, ' {', +// 'tag', 'foo', +// 'qualifier', '.bar', +// 'header', '#hello', +// null, ' { ', +// 'property', 'color', +// 'operator', ':', +// null, ' ', +// 'keyword', 'black', +// null, ' ', +// 'keyword', '!important', +// null, '; ', +// 'property', 'background', +// 'operator', ':', +// null, ' ', +// 'atom', '#f00', +// null, '; ', +// 'property', 'padding', +// 'operator', ':', +// null, ' ', +// 'number', '5px', +// null, '; ', +// 'property', 'margin', +// 'operator', ':', +// null, ' ', +// 'number', '-5px', +// null, '; ', +// 'meta', '-foo-', +// 'property', 'box-sizing', +// 'operator', ':', +// null, ' ', +// 'string-2', 'border-box', +// null, '; } ', +// 'comment', '/* world */', +// null, '}' +// ] +//); \ No newline at end of file diff --git a/codemirror-2.36/mode/diff/diff.js b/codemirror-2.36/mode/diff/diff.js new file mode 100644 index 00000000..3402f3b3 --- /dev/null +++ b/codemirror-2.36/mode/diff/diff.js @@ -0,0 +1,32 @@ +CodeMirror.defineMode("diff", function() { + + var TOKEN_NAMES = { + '+': 'tag', + '-': 'string', + '@': 'meta' + }; + + return { + token: function(stream) { + var tw_pos = stream.string.search(/[\t ]+?$/); + + if (!stream.sol() || tw_pos === 0) { + stream.skipToEnd(); + return ("error " + ( + TOKEN_NAMES[stream.string.charAt(0)] || '')).replace(/ $/, ''); + } + + var token_name = TOKEN_NAMES[stream.peek()] || stream.skipToEnd(); + + if (tw_pos === -1) { + stream.skipToEnd(); + } else { + stream.pos = tw_pos; + } + + return token_name; + } + }; +}); + +CodeMirror.defineMIME("text/x-diff", "diff"); diff --git a/codemirror-2.36/mode/diff/index.html b/codemirror-2.36/mode/diff/index.html new file mode 100644 index 00000000..55602520 --- /dev/null +++ b/codemirror-2.36/mode/diff/index.html @@ -0,0 +1,105 @@ + + + + +MIME types defined: text/x-diff
.
Based on CodeMirror's clike mode. For more information see HPCC Systems web site.
+MIME types defined: text/x-ecl
.
MIME types defined: text/x-erlang
.
Optionally depends on other modes for properly highlighted code blocks.
+ +Parsing/Highlighting Tests: normal, verbose.
+ + + diff --git a/codemirror-2.36/mode/gfm/test.js b/codemirror-2.36/mode/gfm/test.js new file mode 100644 index 00000000..3a261f8f --- /dev/null +++ b/codemirror-2.36/mode/gfm/test.js @@ -0,0 +1,225 @@ +// Initiate ModeTest and set defaults +var MT = ModeTest; +MT.modeName = 'gfm'; +MT.modeOptions = {}; + +// Emphasis characters within a word +MT.testMode( + 'emInWordAsterisk', + 'foo*bar*hello', + [ + null, 'foo', + 'em', '*bar*', + null, 'hello' + ] +); +MT.testMode( + 'emInWordUnderscore', + 'foo_bar_hello', + [ + null, 'foo_bar_hello' + ] +); +MT.testMode( + 'emStrongUnderscore', + '___foo___ bar', + [ + 'strong', '__', + 'emstrong', '_foo__', + 'em', '_', + null, ' bar' + ] +); + +// Fenced code blocks +MT.testMode( + 'fencedCodeBlocks', + '```\nfoo\n\n```\nbar', + [ + 'comment', '```', + 'comment', 'foo', + 'comment', '```', + null, 'bar' + ] +); +// Fenced code block mode switching +MT.testMode( + 'fencedCodeBlockModeSwitching', + '```javascript\nfoo\n\n```\nbar', + [ + 'comment', '```javascript', + 'variable', 'foo', + 'comment', '```', + null, 'bar' + ] +); + +// SHA +MT.testMode( + 'SHA', + 'foo be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2 bar', + [ + null, 'foo ', + 'link', 'be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2', + null, ' bar' + ] +); +// GitHub highlights hashes 7-40 chars in length +MT.testMode( + 'shortSHA', + 'foo be6a8cc bar', + [ + null, 'foo ', + 'link', 'be6a8cc', + null, ' bar' + ] +); +// Invalid SHAs +// +// GitHub does not highlight hashes shorter than 7 chars +MT.testMode( + 'tooShortSHA', + 'foo be6a8c bar', + [ + null, 'foo be6a8c bar' + ] +); +// GitHub does not highlight hashes longer than 40 chars +MT.testMode( + 'longSHA', + 'foo be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd22 bar', + [ + null, 'foo be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd22 bar' + ] +); +MT.testMode( + 'badSHA', + 'foo be6a8cc1c1ecfe9489fb51e4869af15a13fc2cg2 bar', + [ + null, 'foo be6a8cc1c1ecfe9489fb51e4869af15a13fc2cg2 bar' + ] +); +// User@SHA +MT.testMode( + 'userSHA', + 'foo bar@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2 hello', + [ + null, 'foo ', + 'link', 'bar@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2', + null, ' hello' + ] +); +// User/Project@SHA +MT.testMode( + 'userProjectSHA', + 'foo bar/hello@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2 world', + [ + null, 'foo ', + 'link', 'bar/hello@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2', + null, ' world' + ] +); + +// #Num +MT.testMode( + 'num', + 'foo #1 bar', + [ + null, 'foo ', + 'link', '#1', + null, ' bar' + ] +); +// bad #Num +MT.testMode( + 'badNum', + 'foo #1bar hello', + [ + null, 'foo #1bar hello' + ] +); +// User#Num +MT.testMode( + 'userNum', + 'foo bar#1 hello', + [ + null, 'foo ', + 'link', 'bar#1', + null, ' hello' + ] +); +// User/Project#Num +MT.testMode( + 'userProjectNum', + 'foo bar/hello#1 world', + [ + null, 'foo ', + 'link', 'bar/hello#1', + null, ' world' + ] +); + +// Vanilla links +MT.testMode( + 'vanillaLink', + 'foo http://www.example.com/ bar', + [ + null, 'foo ', + 'link', 'http://www.example.com/', + null, ' bar' + ] +); +MT.testMode( + 'vanillaLinkPunctuation', + 'foo http://www.example.com/. bar', + [ + null, 'foo ', + 'link', 'http://www.example.com/', + null, '. bar' + ] +); +MT.testMode( + 'vanillaLinkExtension', + 'foo http://www.example.com/index.html bar', + [ + null, 'foo ', + 'link', 'http://www.example.com/index.html', + null, ' bar' + ] +); +// Not a link +MT.testMode( + 'notALink', + '```css\nfoo {color:black;}\n```http://www.example.com/', + [ + 'comment', '```css', + 'tag', 'foo', + null, ' {', + 'property', 'color', + 'operator', ':', + 'keyword', 'black', + null, ';}', + 'comment', '```', + 'link', 'http://www.example.com/' + ] +); +// Not a link +MT.testMode( + 'notALink', + '``foo `bar` http://www.example.com/`` hello', + [ + 'comment', '``foo `bar` http://www.example.com/``', + null, ' hello' + ] +); +// Not a link +MT.testMode( + 'notALink', + '`foo\nhttp://www.example.com/\n`foo\n\nhttp://www.example.com/', + [ + 'comment', '`foo', + 'link', 'http://www.example.com/', + 'comment', '`foo', + 'link', 'http://www.example.com/' + ] +); \ No newline at end of file diff --git a/codemirror-2.36/mode/go/go.js b/codemirror-2.36/mode/go/go.js new file mode 100644 index 00000000..9863bbf0 --- /dev/null +++ b/codemirror-2.36/mode/go/go.js @@ -0,0 +1,170 @@ +CodeMirror.defineMode("go", function(config, parserConfig) { + var indentUnit = config.indentUnit; + + var keywords = { + "break":true, "case":true, "chan":true, "const":true, "continue":true, + "default":true, "defer":true, "else":true, "fallthrough":true, "for":true, + "func":true, "go":true, "goto":true, "if":true, "import":true, + "interface":true, "map":true, "package":true, "range":true, "return":true, + "select":true, "struct":true, "switch":true, "type":true, "var":true, + "bool":true, "byte":true, "complex64":true, "complex128":true, + "float32":true, "float64":true, "int8":true, "int16":true, "int32":true, + "int64":true, "string":true, "uint8":true, "uint16":true, "uint32":true, + "uint64":true, "int":true, "uint":true, "uintptr":true + }; + + var atoms = { + "true":true, "false":true, "iota":true, "nil":true, "append":true, + "cap":true, "close":true, "complex":true, "copy":true, "imag":true, + "len":true, "make":true, "new":true, "panic":true, "print":true, + "println":true, "real":true, "recover":true + }; + + var blockKeywords = { + "else":true, "for":true, "func":true, "if":true, "interface":true, + "select":true, "struct":true, "switch":true + }; + + var isOperatorChar = /[+\-*&^%:=<>!|\/]/; + + var curPunc; + + function tokenBase(stream, state) { + var ch = stream.next(); + if (ch == '"' || ch == "'" || ch == "`") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + if (/[\d\.]/.test(ch)) { + if (ch == ".") { + stream.match(/^[0-9]+([eE][\-+]?[0-9]+)?/); + } else if (ch == "0") { + stream.match(/^[xX][0-9a-fA-F]+/) || stream.match(/^0[0-7]+/); + } else { + stream.match(/^[0-9]*\.?[0-9]*([eE][\-+]?[0-9]+)?/); + } + return "number"; + } + if (/[\[\]{}\(\),;\:\.]/.test(ch)) { + curPunc = ch; + return null; + } + if (ch == "/") { + if (stream.eat("*")) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } + if (stream.eat("/")) { + stream.skipToEnd(); + return "comment"; + } + } + if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "operator"; + } + stream.eatWhile(/[\w\$_]/); + var cur = stream.current(); + if (keywords.propertyIsEnumerable(cur)) { + if (cur == "case" || cur == "default") curPunc = "case"; + return "keyword"; + } + if (atoms.propertyIsEnumerable(cur)) return "atom"; + return "variable"; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) {end = true; break;} + escaped = !escaped && next == "\\"; + } + if (end || !(escaped || quote == "`")) + state.tokenize = tokenBase; + return "string"; + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function Context(indented, column, type, align, prev) { + this.indented = indented; + this.column = column; + this.type = type; + this.align = align; + this.prev = prev; + } + function pushContext(state, col, type) { + return state.context = new Context(state.indented, col, type, null, state.context); + } + function popContext(state) { + var t = state.context.type; + if (t == ")" || t == "]" || t == "}") + state.indented = state.context.indented; + return state.context = state.context.prev; + } + + // Interface + + return { + startState: function(basecolumn) { + return { + tokenize: null, + context: new Context((basecolumn || 0) - indentUnit, 0, "top", false), + indented: 0, + startOfLine: true + }; + }, + + token: function(stream, state) { + var ctx = state.context; + if (stream.sol()) { + if (ctx.align == null) ctx.align = false; + state.indented = stream.indentation(); + state.startOfLine = true; + if (ctx.type == "case") ctx.type = "}"; + } + if (stream.eatSpace()) return null; + curPunc = null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style == "comment") return style; + if (ctx.align == null) ctx.align = true; + + if (curPunc == "{") pushContext(state, stream.column(), "}"); + else if (curPunc == "[") pushContext(state, stream.column(), "]"); + else if (curPunc == "(") pushContext(state, stream.column(), ")"); + else if (curPunc == "case") ctx.type = "case"; + else if (curPunc == "}" && ctx.type == "}") ctx = popContext(state); + else if (curPunc == ctx.type) popContext(state); + state.startOfLine = false; + return style; + }, + + indent: function(state, textAfter) { + if (state.tokenize != tokenBase && state.tokenize != null) return 0; + var ctx = state.context, firstChar = textAfter && textAfter.charAt(0); + if (ctx.type == "case" && /^(?:case|default)\b/.test(textAfter)) { + state.context.type = "}"; + return ctx.indented; + } + var closing = firstChar == ctx.type; + if (ctx.align) return ctx.column + (closing ? 0 : 1); + else return ctx.indented + (closing ? 0 : indentUnit); + }, + + electricChars: "{}:" + }; +}); + +CodeMirror.defineMIME("text/x-go", "go"); diff --git a/codemirror-2.36/mode/go/index.html b/codemirror-2.36/mode/go/index.html new file mode 100644 index 00000000..24b1cb9d --- /dev/null +++ b/codemirror-2.36/mode/go/index.html @@ -0,0 +1,73 @@ + + + + +MIME type: text/x-go
MIME types defined: text/x-groovy
MIME types defined: text/x-haskell
.
MIME types defined: text/x-haxe
.
Mode for html embedded scripts like JSP and ASP.NET. Depends on HtmlMixed which in turn depends on
+ JavaScript, CSS and XML.
Other dependancies include those of the scriping language chosen.
MIME types defined: application/x-aspx
(ASP.NET),
+ application/x-ejs
(Embedded Javascript), application/x-jsp
(JavaServer Pages)
The HTML mixed mode depends on the XML, JavaScript, and CSS modes.
+ +MIME types defined: text/html
+ (redefined, only takes effect if you load this parser after the
+ XML parser).
+ JavaScript mode supports a two configuration + options: +
json
which will set the mode to expect JSON data rather than a JavaScript program.typescript
which will activate additional syntax highlighting and some other things for TypeScript code (demo).
+ MIME types defined: text/javascript
, application/json
, text/typescript
, application/typescript
.
This is a specialization of the JavaScript mode.
+ + diff --git a/codemirror-2.36/mode/jinja2/index.html b/codemirror-2.36/mode/jinja2/index.html new file mode 100644 index 00000000..7cd1da23 --- /dev/null +++ b/codemirror-2.36/mode/jinja2/index.html @@ -0,0 +1,38 @@ + + + + +MIME types defined: text/x-less
, text/css
(if not previously defined).
Loosely based on Franciszek
+ Wawrzak's CodeMirror
+ 1 mode. One configuration parameter is
+ supported, specials
, to which you can provide an
+ array of strings to have those identifiers highlighted with
+ the lua-special
style.
MIME types defined: text/x-lua
.
Optionally depends on the XML mode for properly highlighted inline XML blocks.
+ +MIME types defined: text/x-markdown
.
Parsing/Highlighting Tests: normal, verbose.
+ + + diff --git a/codemirror-2.36/mode/markdown/markdown.js b/codemirror-2.36/mode/markdown/markdown.js new file mode 100644 index 00000000..d227fc9b --- /dev/null +++ b/codemirror-2.36/mode/markdown/markdown.js @@ -0,0 +1,481 @@ +CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { + + var htmlFound = CodeMirror.mimeModes.hasOwnProperty("text/html"); + var htmlMode = CodeMirror.getMode(cmCfg, htmlFound ? "text/html" : "text/plain"); + var aliases = { + html: "htmlmixed", + js: "javascript", + json: "application/json", + c: "text/x-csrc", + "c++": "text/x-c++src", + java: "text/x-java", + csharp: "text/x-csharp", + "c#": "text/x-csharp" + }; + + var getMode = (function () { + var i, modes = {}, mimes = {}, mime; + + var list = CodeMirror.listModes(); + for (i = 0; i < list.length; i++) { + modes[list[i]] = list[i]; + } + var mimesList = CodeMirror.listMIMEs(); + for (i = 0; i < mimesList.length; i++) { + mime = mimesList[i].mime; + mimes[mime] = mimesList[i].mime; + } + + for (var a in aliases) { + if (aliases[a] in modes || aliases[a] in mimes) + modes[a] = aliases[a]; + } + + return function (lang) { + return modes[lang] ? CodeMirror.getMode(cmCfg, modes[lang]) : null; + }; + }()); + + // Should underscores in words open/close em/strong? + if (modeCfg.underscoresBreakWords === undefined) + modeCfg.underscoresBreakWords = true; + + // Turn on fenced code blocks? ("```" to start/end) + if (modeCfg.fencedCodeBlocks === undefined) modeCfg.fencedCodeBlocks = false; + + var codeDepth = 0; + var prevLineHasContent = false + , thisLineHasContent = false; + + var header = 'header' + , code = 'comment' + , quote = 'quote' + , list = 'string' + , hr = 'hr' + , image = 'tag' + , linkinline = 'link' + , linkemail = 'link' + , linktext = 'link' + , linkhref = 'string' + , em = 'em' + , strong = 'strong' + , emstrong = 'emstrong'; + + var hrRE = /^([*\-=_])(?:\s*\1){2,}\s*$/ + , ulRE = /^[*\-+]\s+/ + , olRE = /^[0-9]+\.\s+/ + , headerRE = /^(?:\={1,}|-{1,})$/ + , textRE = /^[^!\[\]*_\\<>` "'(]+/; + + function switchInline(stream, state, f) { + state.f = state.inline = f; + return f(stream, state); + } + + function switchBlock(stream, state, f) { + state.f = state.block = f; + return f(stream, state); + } + + + // Blocks + + function blankLine(state) { + // Reset linkTitle state + state.linkTitle = false; + // Reset EM state + state.em = false; + // Reset STRONG state + state.strong = false; + // Reset state.quote + state.quote = false; + if (!htmlFound && state.f == htmlBlock) { + state.f = inlineNormal; + state.block = blockNormal; + } + return null; + } + + function blockNormal(stream, state) { + + if (state.list !== false && state.indentationDiff >= 0) { // Continued list + if (state.indentationDiff < 4) { // Only adjust indentation if *not* a code block + state.indentation -= state.indentationDiff; + } + state.list = null; + } else { // No longer a list + state.list = false; + } + + if (state.indentationDiff >= 4) { + state.indentation -= 4; + stream.skipToEnd(); + return code; + } else if (stream.eatSpace()) { + return null; + } else if (stream.peek() === '#' || (prevLineHasContent && stream.match(headerRE)) ) { + state.header = true; + } else if (stream.eat('>')) { + state.indentation++; + state.quote = true; + } else if (stream.peek() === '[') { + return switchInline(stream, state, footnoteLink); + } else if (stream.match(hrRE, true)) { + return hr; + } else if (stream.match(ulRE, true) || stream.match(olRE, true)) { + state.indentation += 4; + state.list = true; + } else if (modeCfg.fencedCodeBlocks && stream.match(/^```([\w+#]*)/, true)) { + // try switching mode + state.localMode = getMode(RegExp.$1); + if (state.localMode) state.localState = state.localMode.startState(); + switchBlock(stream, state, local); + return code; + } + + return switchInline(stream, state, state.inline); + } + + function htmlBlock(stream, state) { + var style = htmlMode.token(stream, state.htmlState); + if (htmlFound && style === 'tag' && state.htmlState.type !== 'openTag' && !state.htmlState.context) { + state.f = inlineNormal; + state.block = blockNormal; + } + if (state.md_inside && stream.current().indexOf(">")!=-1) { + state.f = inlineNormal; + state.block = blockNormal; + state.htmlState.context = undefined; + } + return style; + } + + function local(stream, state) { + if (stream.sol() && stream.match(/^```/, true)) { + state.localMode = state.localState = null; + state.f = inlineNormal; + state.block = blockNormal; + return code; + } else if (state.localMode) { + return state.localMode.token(stream, state.localState); + } else { + stream.skipToEnd(); + return code; + } + } + + function codeBlock(stream, state) { + if(stream.match(codeBlockRE, true)){ + state.f = inlineNormal; + state.block = blockNormal; + switchInline(stream, state, state.inline); + return code; + } + stream.skipToEnd(); + return code; + } + + // Inline + function getType(state) { + var styles = []; + + if (state.strong) { styles.push(state.em ? emstrong : strong); } + else if (state.em) { styles.push(em); } + + if (state.linkText) { styles.push(linktext); } + + if (state.code) { styles.push(code); } + + if (state.header) { styles.push(header); } + if (state.quote) { styles.push(quote); } + if (state.list !== false) { styles.push(list); } + + return styles.length ? styles.join(' ') : null; + } + + function handleText(stream, state) { + if (stream.match(textRE, true)) { + return getType(state); + } + return undefined; + } + + function inlineNormal(stream, state) { + var style = state.text(stream, state); + if (typeof style !== 'undefined') + return style; + + if (state.list) { // List marker (*, +, -, 1., etc) + state.list = null; + return list; + } + + var ch = stream.next(); + + if (ch === '\\') { + stream.next(); + return getType(state); + } + + // Matches link titles present on next line + if (state.linkTitle) { + state.linkTitle = false; + var matchCh = ch; + if (ch === '(') { + matchCh = ')'; + } + matchCh = (matchCh+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"); + var regex = '^\\s*(?:[^' + matchCh + '\\\\]+|\\\\\\\\|\\\\.)' + matchCh; + if (stream.match(new RegExp(regex), true)) { + return linkhref; + } + } + + // If this block is changed, it may need to be updated in GFM mode + if (ch === '`') { + var t = getType(state); + var before = stream.pos; + stream.eatWhile('`'); + var difference = 1 + stream.pos - before; + if (!state.code) { + codeDepth = difference; + state.code = true; + return getType(state); + } else { + if (difference === codeDepth) { // Must be exact + state.code = false; + return t; + } + return getType(state); + } + } else if (state.code) { + return getType(state); + } + + if (ch === '!' && stream.match(/\[.*\] ?(?:\(|\[)/, false)) { + stream.match(/\[.*\]/); + state.inline = state.f = linkHref; + return image; + } + + if (ch === '[' && stream.match(/.*\](\(| ?\[)/, false)) { + state.linkText = true; + return getType(state); + } + + if (ch === ']' && state.linkText) { + var type = getType(state); + state.linkText = false; + state.inline = state.f = linkHref; + return type; + } + + if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, true)) { + return switchInline(stream, state, inlineElement(linkinline, '>')); + } + + if (ch === '<' && stream.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/, true)) { + return switchInline(stream, state, inlineElement(linkemail, '>')); + } + + if (ch === '<' && stream.match(/^\w/, false)) { + var md_inside = false; + if (stream.string.indexOf(">")!=-1) { + var atts = stream.string.substring(1,stream.string.indexOf(">")); + if (/markdown\s*=\s*('|"){0,1}1('|"){0,1}/.test(atts)) { + state.md_inside = true; + } + } + stream.backUp(1); + return switchBlock(stream, state, htmlBlock); + } + + if (ch === '<' && stream.match(/^\/\w*?>/)) { + state.md_inside = false; + return "tag"; + } + + var ignoreUnderscore = false; + if (!modeCfg.underscoresBreakWords) { + if (ch === '_' && stream.peek() !== '_' && stream.match(/(\w)/, false)) { + var prevPos = stream.pos - 2; + if (prevPos >= 0) { + var prevCh = stream.string.charAt(prevPos); + if (prevCh !== '_' && prevCh.match(/(\w)/, false)) { + ignoreUnderscore = true; + } + } + } + } + var t = getType(state); + if (ch === '*' || (ch === '_' && !ignoreUnderscore)) { + if (state.strong === ch && stream.eat(ch)) { // Remove STRONG + state.strong = false; + return t; + } else if (!state.strong && stream.eat(ch)) { // Add STRONG + state.strong = ch; + return getType(state); + } else if (state.em === ch) { // Remove EM + state.em = false; + return t; + } else if (!state.em) { // Add EM + state.em = ch; + return getType(state); + } + } else if (ch === ' ') { + if (stream.eat('*') || stream.eat('_')) { // Probably surrounded by spaces + if (stream.peek() === ' ') { // Surrounded by spaces, ignore + return getType(state); + } else { // Not surrounded by spaces, back up pointer + stream.backUp(1); + } + } + } + + return getType(state); + } + + function linkHref(stream, state) { + // Check if space, and return NULL if so (to avoid marking the space) + if(stream.eatSpace()){ + return null; + } + var ch = stream.next(); + if (ch === '(' || ch === '[') { + return switchInline(stream, state, inlineElement(linkhref, ch === '(' ? ')' : ']')); + } + return 'error'; + } + + function footnoteLink(stream, state) { + if (stream.match(/^[^\]]*\]:/, true)) { + state.f = footnoteUrl; + return linktext; + } + return switchInline(stream, state, inlineNormal); + } + + function footnoteUrl(stream, state) { + // Check if space, and return NULL if so (to avoid marking the space) + if(stream.eatSpace()){ + return null; + } + // Match URL + stream.match(/^[^\s]+/, true); + // Check for link title + if (stream.peek() === undefined) { // End of line, set flag to check next line + state.linkTitle = true; + } else { // More content on line, check if link title + stream.match(/^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?/, true); + } + state.f = state.inline = inlineNormal; + return linkhref; + } + + var savedInlineRE = []; + function inlineRE(endChar) { + if (!savedInlineRE[endChar]) { + // Escape endChar for RegExp (taken from http://stackoverflow.com/a/494122/526741) + endChar = (endChar+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"); + // Match any non-endChar, escaped character, as well as the closing + // endChar. + savedInlineRE[endChar] = new RegExp('^(?:[^\\\\]|\\\\.)*?(' + endChar + ')'); + } + return savedInlineRE[endChar]; + } + + function inlineElement(type, endChar, next) { + next = next || inlineNormal; + return function(stream, state) { + stream.match(inlineRE(endChar)); + state.inline = state.f = next; + return type; + }; + } + + return { + startState: function() { + prevLineHasContent = false; + thisLineHasContent = false; + return { + f: blockNormal, + + block: blockNormal, + htmlState: CodeMirror.startState(htmlMode), + indentation: 0, + + inline: inlineNormal, + text: handleText, + + linkText: false, + linkTitle: false, + em: false, + strong: false, + header: false, + list: false, + quote: false + }; + }, + + copyState: function(s) { + return { + f: s.f, + + block: s.block, + htmlState: CodeMirror.copyState(htmlMode, s.htmlState), + indentation: s.indentation, + + localMode: s.localMode, + localState: s.localMode ? CodeMirror.copyState(s.localMode, s.localState) : null, + + inline: s.inline, + text: s.text, + linkTitle: s.linkTitle, + em: s.em, + strong: s.strong, + header: s.header, + list: s.list, + quote: s.quote, + md_inside: s.md_inside + }; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (stream.match(/^\s*$/, true)) { + prevLineHasContent = false; + return blankLine(state); + } else { + if(thisLineHasContent){ + prevLineHasContent = true; + thisLineHasContent = false; + } + thisLineHasContent = true; + } + + // Reset state.header + state.header = false; + + // Reset state.code + state.code = false; + + state.f = state.block; + var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length; + var difference = Math.floor((indentation - state.indentation) / 4) * 4; + if (difference > 4) difference = 4; + indentation = state.indentation + difference; + state.indentationDiff = indentation - state.indentation; + state.indentation = indentation; + if (indentation > 0) { return null; } + } + return state.f(stream, state); + }, + + blankLine: blankLine, + + getType: getType + }; + +}, "xml"); + +CodeMirror.defineMIME("text/x-markdown", "markdown"); diff --git a/codemirror-2.36/mode/markdown/test.js b/codemirror-2.36/mode/markdown/test.js new file mode 100644 index 00000000..7572db51 --- /dev/null +++ b/codemirror-2.36/mode/markdown/test.js @@ -0,0 +1,1266 @@ +// Initiate ModeTest and set defaults +var MT = ModeTest; +MT.modeName = 'markdown'; +MT.modeOptions = {}; + +MT.testMode( + 'plainText', + 'foo', + [ + null, 'foo' + ] +); + +// Code blocks using 4 spaces (regardless of CodeMirror.tabSize value) +MT.testMode( + 'codeBlocksUsing4Spaces', + ' foo', + [ + null, ' ', + 'comment', 'foo' + ] +); +// Code blocks using 4 spaces with internal indentation +MT.testMode( + 'codeBlocksUsing4SpacesIndentation', + ' bar\n hello\n world\n foo\nbar', + [ + null, ' ', + 'comment', 'bar', + null, ' ', + 'comment', 'hello', + null, ' ', + 'comment', 'world', + null, ' ', + 'comment', 'foo', + null, 'bar' + ] +); +// Code blocks using 4 spaces with internal indentation +MT.testMode( + 'codeBlocksUsing4SpacesIndentation', + ' foo\n bar\n hello\n world', + [ + null, ' foo', + null, ' ', + 'comment', 'bar', + null, ' ', + 'comment', 'hello', + null, ' ', + 'comment', 'world' + ] +); + +// Code blocks using 1 tab (regardless of CodeMirror.indentWithTabs value) +MT.testMode( + 'codeBlocksUsing1Tab', + '\tfoo', + [ + null, '\t', + 'comment', 'foo' + ] +); + +// Inline code using backticks +MT.testMode( + 'inlineCodeUsingBackticks', + 'foo `bar`', + [ + null, 'foo ', + 'comment', '`bar`' + ] +); + +// Block code using single backtick (shouldn't work) +MT.testMode( + 'blockCodeSingleBacktick', + '`\nfoo\n`', + [ + 'comment', '`', + null, 'foo', + 'comment', '`' + ] +); + +// Unclosed backticks +// Instead of simply marking as CODE, it would be nice to have an +// incomplete flag for CODE, that is styled slightly different. +MT.testMode( + 'unclosedBackticks', + 'foo `bar', + [ + null, 'foo ', + 'comment', '`bar' + ] +); + +// Per documentation: "To include a literal backtick character within a +// code span, you can use multiple backticks as the opening and closing +// delimiters" +MT.testMode( + 'doubleBackticks', + '``foo ` bar``', + [ + 'comment', '``foo ` bar``' + ] +); + +// Tests based on Dingus +// http://daringfireball.net/projects/markdown/dingus +// +// Multiple backticks within an inline code block +MT.testMode( + 'consecutiveBackticks', + '`foo```bar`', + [ + 'comment', '`foo```bar`' + ] +); +// Multiple backticks within an inline code block with a second code block +MT.testMode( + 'consecutiveBackticks', + '`foo```bar` hello `world`', + [ + 'comment', '`foo```bar`', + null, ' hello ', + 'comment', '`world`' + ] +); +// Unclosed with several different groups of backticks +MT.testMode( + 'unclosedBackticks', + '``foo ``` bar` hello', + [ + 'comment', '``foo ``` bar` hello' + ] +); +// Closed with several different groups of backticks +MT.testMode( + 'closedBackticks', + '``foo ``` bar` hello`` world', + [ + 'comment', '``foo ``` bar` hello``', + null, ' world' + ] +); + +// atx headers +// http://daringfireball.net/projects/markdown/syntax#header +// +// H1 +MT.testMode( + 'atxH1', + '# foo', + [ + 'header', '# foo' + ] +); +// H2 +MT.testMode( + 'atxH2', + '## foo', + [ + 'header', '## foo' + ] +); +// H3 +MT.testMode( + 'atxH3', + '### foo', + [ + 'header', '### foo' + ] +); +// H4 +MT.testMode( + 'atxH4', + '#### foo', + [ + 'header', '#### foo' + ] +); +// H5 +MT.testMode( + 'atxH5', + '##### foo', + [ + 'header', '##### foo' + ] +); +// H6 +MT.testMode( + 'atxH6', + '###### foo', + [ + 'header', '###### foo' + ] +); +// H6 - 7x '#' should still be H6, per Dingus +// http://daringfireball.net/projects/markdown/dingus +MT.testMode( + 'atxH6NotH7', + '####### foo', + [ + 'header', '####### foo' + ] +); + +// Setext headers - H1, H2 +// Per documentation, "Any number of underlining =’s or -’s will work." +// http://daringfireball.net/projects/markdown/syntax#header +// Ideally, the text would be marked as `header` as well, but this is +// not really feasible at the moment. So, instead, we're testing against +// what works today, to avoid any regressions. +// +// Check if single underlining = works +MT.testMode( + 'setextH1', + 'foo\n=', + [ + null, 'foo', + 'header', '=' + ] +); +// Check if 3+ ='s work +MT.testMode( + 'setextH1', + 'foo\n===', + [ + null, 'foo', + 'header', '===' + ] +); +// Check if single underlining - works +MT.testMode( + 'setextH2', + 'foo\n-', + [ + null, 'foo', + 'header', '-' + ] +); +// Check if 3+ -'s work +MT.testMode( + 'setextH2', + 'foo\n---', + [ + null, 'foo', + 'header', '---' + ] +); + +// Single-line blockquote with trailing space +MT.testMode( + 'blockquoteSpace', + '> foo', + [ + 'quote', '> foo' + ] +); + +// Single-line blockquote +MT.testMode( + 'blockquoteNoSpace', + '>foo', + [ + 'quote', '>foo' + ] +); + +// Single-line blockquote followed by normal paragraph +MT.testMode( + 'blockquoteThenParagraph', + '>foo\n\nbar', + [ + 'quote', '>foo', + null, 'bar' + ] +); + +// Multi-line blockquote (lazy mode) +MT.testMode( + 'multiBlockquoteLazy', + '>foo\nbar', + [ + 'quote', '>foo', + 'quote', 'bar' + ] +); + +// Multi-line blockquote followed by normal paragraph (lazy mode) +MT.testMode( + 'multiBlockquoteLazyThenParagraph', + '>foo\nbar\n\nhello', + [ + 'quote', '>foo', + 'quote', 'bar', + null, 'hello' + ] +); + +// Multi-line blockquote (non-lazy mode) +MT.testMode( + 'multiBlockquote', + '>foo\n>bar', + [ + 'quote', '>foo', + 'quote', '>bar' + ] +); + +// Multi-line blockquote followed by normal paragraph (non-lazy mode) +MT.testMode( + 'multiBlockquoteThenParagraph', + '>foo\n>bar\n\nhello', + [ + 'quote', '>foo', + 'quote', '>bar', + null, 'hello' + ] +); + +// Check list types +MT.testMode( + 'listAsterisk', + '* foo\n* bar', + [ + 'string', '* foo', + 'string', '* bar' + ] +); +MT.testMode( + 'listPlus', + '+ foo\n+ bar', + [ + 'string', '+ foo', + 'string', '+ bar' + ] +); +MT.testMode( + 'listDash', + '- foo\n- bar', + [ + 'string', '- foo', + 'string', '- bar' + ] +); +MT.testMode( + 'listNumber', + '1. foo\n2. bar', + [ + 'string', '1. foo', + 'string', '2. bar' + ] +); + +// Formatting in lists (*) +MT.testMode( + 'listAsteriskFormatting', + '* *foo* bar\n\n* **foo** bar\n\n* ***foo*** bar\n\n* `foo` bar', + [ + 'string', '* ', + 'string em', '*foo*', + 'string', ' bar', + 'string', '* ', + 'string strong', '**foo**', + 'string', ' bar', + 'string', '* ', + 'string strong', '**', + 'string emstrong', '*foo**', + 'string em', '*', + 'string', ' bar', + 'string', '* ', + 'string comment', '`foo`', + 'string', ' bar' + ] +); +// Formatting in lists (+) +MT.testMode( + 'listPlusFormatting', + '+ *foo* bar\n\n+ **foo** bar\n\n+ ***foo*** bar\n\n+ `foo` bar', + [ + 'string', '+ ', + 'string em', '*foo*', + 'string', ' bar', + 'string', '+ ', + 'string strong', '**foo**', + 'string', ' bar', + 'string', '+ ', + 'string strong', '**', + 'string emstrong', '*foo**', + 'string em', '*', + 'string', ' bar', + 'string', '+ ', + 'string comment', '`foo`', + 'string', ' bar' + ] +); +// Formatting in lists (-) +MT.testMode( + 'listDashFormatting', + '- *foo* bar\n\n- **foo** bar\n\n- ***foo*** bar\n\n- `foo` bar', + [ + 'string', '- ', + 'string em', '*foo*', + 'string', ' bar', + 'string', '- ', + 'string strong', '**foo**', + 'string', ' bar', + 'string', '- ', + 'string strong', '**', + 'string emstrong', '*foo**', + 'string em', '*', + 'string', ' bar', + 'string', '- ', + 'string comment', '`foo`', + 'string', ' bar' + ] +); +// Formatting in lists (1.) +MT.testMode( + 'listNumberFormatting', + '1. *foo* bar\n\n2. **foo** bar\n\n3. ***foo*** bar\n\n4. `foo` bar', + [ + 'string', '1. ', + 'string em', '*foo*', + 'string', ' bar', + 'string', '2. ', + 'string strong', '**foo**', + 'string', ' bar', + 'string', '3. ', + 'string strong', '**', + 'string emstrong', '*foo**', + 'string em', '*', + 'string', ' bar', + 'string', '4. ', + 'string comment', '`foo`', + 'string', ' bar' + ] +); + +// Paragraph lists +MT.testMode( + 'listParagraph', + '* foo\n\n* bar', + [ + 'string', '* foo', + 'string', '* bar' + ] +); + +// Multi-paragraph lists +// +// 4 spaces +MT.testMode( + 'listMultiParagraph', + '* foo\n\n* bar\n\n hello', + [ + 'string', '* foo', + 'string', '* bar', + null, ' ', + 'string', 'hello' + ] +); +// 4 spaces, extra blank lines (should still be list, per Dingus) +MT.testMode( + 'listMultiParagraphExtra', + '* foo\n\n* bar\n\n\n hello', + [ + 'string', '* foo', + 'string', '* bar', + null, ' ', + 'string', 'hello' + ] +); +// 4 spaces, plus 1 space (should still be list, per Dingus) +MT.testMode( + 'listMultiParagraphExtraSpace', + '* foo\n\n* bar\n\n hello\n\n world', + [ + 'string', '* foo', + 'string', '* bar', + null, ' ', + 'string', 'hello', + null, ' ', + 'string', 'world' + ] +); +// 1 tab +MT.testMode( + 'listTab', + '* foo\n\n* bar\n\n\thello', + [ + 'string', '* foo', + 'string', '* bar', + null, '\t', + 'string', 'hello' + ] +); +// No indent +MT.testMode( + 'listNoIndent', + '* foo\n\n* bar\n\nhello', + [ + 'string', '* foo', + 'string', '* bar', + null, 'hello' + ] +); +// Blockquote +MT.testMode( + 'blockquote', + '* foo\n\n* bar\n\n > hello', + [ + 'string', '* foo', + 'string', '* bar', + null, ' ', + 'string quote', '> hello' + ] +); +// Code block +MT.testMode( + 'blockquoteCode', + '* foo\n\n* bar\n\n > hello\n\n world', + [ + 'string', '* foo', + 'string', '* bar', + null, ' ', + 'comment', '> hello', + null, ' ', + 'string', 'world' + ] +); +// Code block followed by text +MT.testMode( + 'blockquoteCodeText', + '* foo\n\n bar\n\n hello\n\n world', + [ + 'string', '* foo', + null, ' ', + 'string', 'bar', + null, ' ', + 'comment', 'hello', + null, ' ', + 'string', 'world' + ] +); + +// Nested list +// +// * +MT.testMode( + 'listAsteriskNested', + '* foo\n\n * bar', + [ + 'string', '* foo', + null, ' ', + 'string', '* bar' + ] +); +// + +MT.testMode( + 'listPlusNested', + '+ foo\n\n + bar', + [ + 'string', '+ foo', + null, ' ', + 'string', '+ bar' + ] +); +// - +MT.testMode( + 'listDashNested', + '- foo\n\n - bar', + [ + 'string', '- foo', + null, ' ', + 'string', '- bar' + ] +); +// 1. +MT.testMode( + 'listNumberNested', + '1. foo\n\n 2. bar', + [ + 'string', '1. foo', + null, ' ', + 'string', '2. bar' + ] +); +// Mixed +MT.testMode( + 'listMixed', + '* foo\n\n + bar\n\n - hello\n\n 1. world', + [ + 'string', '* foo', + null, ' ', + 'string', '+ bar', + null, ' ', + 'string', '- hello', + null, ' ', + 'string', '1. world' + ] +); +// Blockquote +MT.testMode( + 'listBlockquote', + '* foo\n\n + bar\n\n > hello', + [ + 'string', '* foo', + null, ' ', + 'string', '+ bar', + null, ' ', + 'quote string', '> hello' + ] +); +// Code +MT.testMode( + 'listCode', + '* foo\n\n + bar\n\n hello', + [ + 'string', '* foo', + null, ' ', + 'string', '+ bar', + null, ' ', + 'comment', 'hello' + ] +); +// Code with internal indentation +MT.testMode( + 'listCodeIndentation', + '* foo\n\n bar\n hello\n world\n foo\n bar', + [ + 'string', '* foo', + null, ' ', + 'comment', 'bar', + null, ' ', + 'comment', 'hello', + null, ' ', + 'comment', 'world', + null, ' ', + 'comment', 'foo', + null, ' ', + 'string', 'bar' + ] +); +// Code followed by text +MT.testMode( + 'listCodeText', + '* foo\n\n bar\n\nhello', + [ + 'string', '* foo', + null, ' ', + 'comment', 'bar', + null, 'hello' + ] +); + +// Following tests directly from official Markdown documentation +// http://daringfireball.net/projects/markdown/syntax#hr +MT.testMode( + 'hrSpace', + '* * *', + [ + 'hr', '* * *' + ] +); + +MT.testMode( + 'hr', + '***', + [ + 'hr', '***' + ] +); + +MT.testMode( + 'hrLong', + '*****', + [ + 'hr', '*****' + ] +); + +MT.testMode( + 'hrSpaceDash', + '- - -', + [ + 'hr', '- - -' + ] +); + +MT.testMode( + 'hrDashLong', + '---------------------------------------', + [ + 'hr', '---------------------------------------' + ] +); + +// Inline link with title +MT.testMode( + 'linkTitle', + '[foo](http://example.com/ "bar") hello', + [ + 'link', '[foo]', + 'string', '(http://example.com/ "bar")', + null, ' hello' + ] +); + +// Inline link without title +MT.testMode( + 'linkNoTitle', + '[foo](http://example.com/) bar', + [ + 'link', '[foo]', + 'string', '(http://example.com/)', + null, ' bar' + ] +); + +// Inline link with Em +MT.testMode( + 'linkEm', + '[*foo*](http://example.com/) bar', + [ + 'link', '[', + 'link em', '*foo*', + 'link', ']', + 'string', '(http://example.com/)', + null, ' bar' + ] +); + +// Inline link with Strong +MT.testMode( + 'linkStrong', + '[**foo**](http://example.com/) bar', + [ + 'link', '[', + 'link strong', '**foo**', + 'link', ']', + 'string', '(http://example.com/)', + null, ' bar' + ] +); + +// Inline link with EmStrong +MT.testMode( + 'linkEmStrong', + '[***foo***](http://example.com/) bar', + [ + 'link', '[', + 'link strong', '**', + 'link emstrong', '*foo**', + 'link em', '*', + 'link', ']', + 'string', '(http://example.com/)', + null, ' bar' + ] +); + +// Image with title +MT.testMode( + 'imageTitle', + '![foo](http://example.com/ "bar") hello', + [ + 'tag', '![foo]', + 'string', '(http://example.com/ "bar")', + null, ' hello' + ] +); + +// Image without title +MT.testMode( + 'imageNoTitle', + '![foo](http://example.com/) bar', + [ + 'tag', '![foo]', + 'string', '(http://example.com/)', + null, ' bar' + ] +); + +// Image with asterisks +MT.testMode( + 'imageAsterisks', + '![*foo*](http://example.com/) bar', + [ + 'tag', '![*foo*]', + 'string', '(http://example.com/)', + null, ' bar' + ] +); + +// Not a link. Should be normal text due to square brackets being used +// regularly in text, especially in quoted material, and no space is allowed +// between square brackets and parentheses (per Dingus). +MT.testMode( + 'notALink', + '[foo] (bar)', + [ + null, '[foo] (bar)' + ] +); + +// Reference-style links +MT.testMode( + 'linkReference', + '[foo][bar] hello', + [ + 'link', '[foo]', + 'string', '[bar]', + null, ' hello' + ] +); +// Reference-style links with Em +MT.testMode( + 'linkReferenceEm', + '[*foo*][bar] hello', + [ + 'link', '[', + 'link em', '*foo*', + 'link', ']', + 'string', '[bar]', + null, ' hello' + ] +); +// Reference-style links with Strong +MT.testMode( + 'linkReferenceStrong', + '[**foo**][bar] hello', + [ + 'link', '[', + 'link strong', '**foo**', + 'link', ']', + 'string', '[bar]', + null, ' hello' + ] +); +// Reference-style links with EmStrong +MT.testMode( + 'linkReferenceEmStrong', + '[***foo***][bar] hello', + [ + 'link', '[', + 'link strong', '**', + 'link emstrong', '*foo**', + 'link em', '*', + 'link', ']', + 'string', '[bar]', + null, ' hello' + ] +); + +// Reference-style links with optional space separator (per docuentation) +// "You can optionally use a space to separate the sets of brackets" +MT.testMode( + 'linkReferenceSpace', + '[foo] [bar] hello', + [ + 'link', '[foo]', + null, ' ', + 'string', '[bar]', + null, ' hello' + ] +); +// Should only allow a single space ("...use *a* space...") +MT.testMode( + 'linkReferenceDoubleSpace', + '[foo] [bar] hello', + [ + null, '[foo] [bar] hello' + ] +); + +// Reference-style links with implicit link name +MT.testMode( + 'linkImplicit', + '[foo][] hello', + [ + 'link', '[foo]', + 'string', '[]', + null, ' hello' + ] +); + +// @todo It would be nice if, at some point, the document was actually +// checked to see if the referenced link exists + +// Link label, for reference-style links (taken from documentation) +// +// No title +MT.testMode( + 'labelNoTitle', + '[foo]: http://example.com/', + [ + 'link', '[foo]:', + null, ' ', + 'string', 'http://example.com/' + ] +); +// Space in ID and title +MT.testMode( + 'labelSpaceTitle', + '[foo bar]: http://example.com/ "hello"', + [ + 'link', '[foo bar]:', + null, ' ', + 'string', 'http://example.com/ "hello"' + ] +); +// Double title +MT.testMode( + 'labelDoubleTitle', + '[foo bar]: http://example.com/ "hello" "world"', + [ + 'link', '[foo bar]:', + null, ' ', + 'string', 'http://example.com/ "hello"', + null, ' "world"' + ] +); +// Double quotes around title +MT.testMode( + 'labelTitleDoubleQuotes', + '[foo]: http://example.com/ "bar"', + [ + 'link', '[foo]:', + null, ' ', + 'string', 'http://example.com/ "bar"' + ] +); +// Single quotes around title +MT.testMode( + 'labelTitleSingleQuotes', + '[foo]: http://example.com/ \'bar\'', + [ + 'link', '[foo]:', + null, ' ', + 'string', 'http://example.com/ \'bar\'' + ] +); +// Parentheses around title +MT.testMode( + 'labelTitleParenthese', + '[foo]: http://example.com/ (bar)', + [ + 'link', '[foo]:', + null, ' ', + 'string', 'http://example.com/ (bar)' + ] +); +// Invalid title +MT.testMode( + 'labelTitleInvalid', + '[foo]: http://example.com/ bar', + [ + 'link', '[foo]:', + null, ' ', + 'string', 'http://example.com/', + null, ' bar' + ] +); +// Angle brackets around URL +MT.testMode( + 'labelLinkAngleBrackets', + '[foo]:MIME types defined: text/x-mysql
.
MIME types defined: text/n-triples
.
MIME types defined: text/x-ocaml
.
MIME types defined: text/x-pascal
.
MIME types defined: text/x-perl
.
Simple HTML/PHP mode based on + the C-like mode. Depends on XML, + JavaScript, CSS, and C-like modes.
+ +MIME types defined: application/x-httpd-php
(HTML with PHP code), text/x-php
(plain, non-wrapped PHP code).
+ Simple mode that handles Pig Latin language. +
+ +MIME type defined: text/x-pig
+ (PIG code)
+
diff --git a/codemirror-2.36/mode/pig/pig.js b/codemirror-2.36/mode/pig/pig.js
new file mode 100644
index 00000000..d55413f1
--- /dev/null
+++ b/codemirror-2.36/mode/pig/pig.js
@@ -0,0 +1,172 @@
+/*
+ * Pig Latin Mode for CodeMirror 2
+ * @author Prasanth Jayachandran
+ * @link https://github.com/prasanthj/pig-codemirror-2
+ * This implementation is adapted from PL/SQL mode in CodeMirror 2.
+*/
+CodeMirror.defineMode("pig", function(config, parserConfig) {
+ var indentUnit = config.indentUnit,
+ keywords = parserConfig.keywords,
+ builtins = parserConfig.builtins,
+ types = parserConfig.types,
+ multiLineStrings = parserConfig.multiLineStrings;
+
+ var isOperatorChar = /[*+\-%<>=&?:\/!|]/;
+
+ function chain(stream, state, f) {
+ state.tokenize = f;
+ return f(stream, state);
+ }
+
+ var type;
+ function ret(tp, style) {
+ type = tp;
+ return style;
+ }
+
+ function tokenComment(stream, state) {
+ var isEnd = false;
+ var ch;
+ while(ch = stream.next()) {
+ if(ch == "/" && isEnd) {
+ state.tokenize = tokenBase;
+ break;
+ }
+ isEnd = (ch == "*");
+ }
+ return ret("comment", "comment");
+ }
+
+ function tokenString(quote) {
+ return function(stream, state) {
+ var escaped = false, next, end = false;
+ while((next = stream.next()) != null) {
+ if (next == quote && !escaped) {
+ end = true; break;
+ }
+ escaped = !escaped && next == "\\";
+ }
+ if (end || !(escaped || multiLineStrings))
+ state.tokenize = tokenBase;
+ return ret("string", "error");
+ };
+ }
+
+ function tokenBase(stream, state) {
+ var ch = stream.next();
+
+ // is a start of string?
+ if (ch == '"' || ch == "'")
+ return chain(stream, state, tokenString(ch));
+ // is it one of the special chars
+ else if(/[\[\]{}\(\),;\.]/.test(ch))
+ return ret(ch);
+ // is it a number?
+ else if(/\d/.test(ch)) {
+ stream.eatWhile(/[\w\.]/);
+ return ret("number", "number");
+ }
+ // multi line comment or operator
+ else if (ch == "/") {
+ if (stream.eat("*")) {
+ return chain(stream, state, tokenComment);
+ }
+ else {
+ stream.eatWhile(isOperatorChar);
+ return ret("operator", "operator");
+ }
+ }
+ // single line comment or operator
+ else if (ch=="-") {
+ if(stream.eat("-")){
+ stream.skipToEnd();
+ return ret("comment", "comment");
+ }
+ else {
+ stream.eatWhile(isOperatorChar);
+ return ret("operator", "operator");
+ }
+ }
+ // is it an operator
+ else if (isOperatorChar.test(ch)) {
+ stream.eatWhile(isOperatorChar);
+ return ret("operator", "operator");
+ }
+ else {
+ // get the while word
+ stream.eatWhile(/[\w\$_]/);
+ // is it one of the listed keywords?
+ if (keywords && keywords.propertyIsEnumerable(stream.current().toUpperCase())) {
+ if (stream.eat(")") || stream.eat(".")) {
+ //keywords can be used as variables like flatten(group), group.$0 etc..
+ }
+ else {
+ return ("keyword", "keyword");
+ }
+ }
+ // is it one of the builtin functions?
+ if (builtins && builtins.propertyIsEnumerable(stream.current().toUpperCase()))
+ {
+ return ("keyword", "variable-2");
+ }
+ // is it one of the listed types?
+ if (types && types.propertyIsEnumerable(stream.current().toUpperCase()))
+ return ("keyword", "variable-3");
+ // default is a 'variable'
+ return ret("variable", "pig-word");
+ }
+ }
+
+ // Interface
+ return {
+ startState: function(basecolumn) {
+ return {
+ tokenize: tokenBase,
+ startOfLine: true
+ };
+ },
+
+ token: function(stream, state) {
+ if(stream.eatSpace()) return null;
+ var style = state.tokenize(stream, state);
+ return style;
+ }
+ };
+});
+
+(function() {
+ function keywords(str) {
+ var obj = {}, words = str.split(" ");
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
+ return obj;
+ }
+
+ // builtin funcs taken from trunk revision 1303237
+ var pBuiltins = "ABS ACOS ARITY ASIN ATAN AVG BAGSIZE BINSTORAGE BLOOM BUILDBLOOM CBRT CEIL "
+ + "CONCAT COR COS COSH COUNT COUNT_STAR COV CONSTANTSIZE CUBEDIMENSIONS DIFF DISTINCT DOUBLEABS "
+ + "DOUBLEAVG DOUBLEBASE DOUBLEMAX DOUBLEMIN DOUBLEROUND DOUBLESUM EXP FLOOR FLOATABS FLOATAVG "
+ + "FLOATMAX FLOATMIN FLOATROUND FLOATSUM GENERICINVOKER INDEXOF INTABS INTAVG INTMAX INTMIN "
+ + "INTSUM INVOKEFORDOUBLE INVOKEFORFLOAT INVOKEFORINT INVOKEFORLONG INVOKEFORSTRING INVOKER "
+ + "ISEMPTY JSONLOADER JSONMETADATA JSONSTORAGE LAST_INDEX_OF LCFIRST LOG LOG10 LOWER LONGABS "
+ + "LONGAVG LONGMAX LONGMIN LONGSUM MAX MIN MAPSIZE MONITOREDUDF NONDETERMINISTIC OUTPUTSCHEMA "
+ + "PIGSTORAGE PIGSTREAMING RANDOM REGEX_EXTRACT REGEX_EXTRACT_ALL REPLACE ROUND SIN SINH SIZE "
+ + "SQRT STRSPLIT SUBSTRING SUM STRINGCONCAT STRINGMAX STRINGMIN STRINGSIZE TAN TANH TOBAG "
+ + "TOKENIZE TOMAP TOP TOTUPLE TRIM TEXTLOADER TUPLESIZE UCFIRST UPPER UTF8STORAGECONVERTER ";
+
+ // taken from QueryLexer.g
+ var pKeywords = "VOID IMPORT RETURNS DEFINE LOAD FILTER FOREACH ORDER CUBE DISTINCT COGROUP "
+ + "JOIN CROSS UNION SPLIT INTO IF OTHERWISE ALL AS BY USING INNER OUTER ONSCHEMA PARALLEL "
+ + "PARTITION GROUP AND OR NOT GENERATE FLATTEN ASC DESC IS STREAM THROUGH STORE MAPREDUCE "
+ + "SHIP CACHE INPUT OUTPUT STDERROR STDIN STDOUT LIMIT SAMPLE LEFT RIGHT FULL EQ GT LT GTE LTE "
+ + "NEQ MATCHES TRUE FALSE ";
+
+ // data types
+ var pTypes = "BOOLEAN INT LONG FLOAT DOUBLE CHARARRAY BYTEARRAY BAG TUPLE MAP ";
+
+ CodeMirror.defineMIME("text/x-pig", {
+ name: "pig",
+ builtins: keywords(pBuiltins),
+ keywords: keywords(pKeywords),
+ types: keywords(pTypes)
+ });
+}());
diff --git a/codemirror-2.36/mode/plsql/index.html b/codemirror-2.36/mode/plsql/index.html
new file mode 100644
index 00000000..3fd00a79
--- /dev/null
+++ b/codemirror-2.36/mode/plsql/index.html
@@ -0,0 +1,63 @@
+
+
+
+ Simple mode that handles Oracle PL/SQL language (and Oracle SQL, of course). +
+ +MIME type defined: text/x-plsql
+ (PLSQL code)
+
diff --git a/codemirror-2.36/mode/plsql/plsql.js b/codemirror-2.36/mode/plsql/plsql.js
new file mode 100644
index 00000000..013deaf9
--- /dev/null
+++ b/codemirror-2.36/mode/plsql/plsql.js
@@ -0,0 +1,217 @@
+CodeMirror.defineMode("plsql", function(config, parserConfig) {
+ var indentUnit = config.indentUnit,
+ keywords = parserConfig.keywords,
+ functions = parserConfig.functions,
+ types = parserConfig.types,
+ sqlplus = parserConfig.sqlplus,
+ multiLineStrings = parserConfig.multiLineStrings;
+ var isOperatorChar = /[+\-*&%=<>!?:\/|]/;
+ function chain(stream, state, f) {
+ state.tokenize = f;
+ return f(stream, state);
+ }
+
+ var type;
+ function ret(tp, style) {
+ type = tp;
+ return style;
+ }
+
+ function tokenBase(stream, state) {
+ var ch = stream.next();
+ // start of string?
+ if (ch == '"' || ch == "'")
+ return chain(stream, state, tokenString(ch));
+ // is it one of the special signs []{}().,;? Seperator?
+ else if (/[\[\]{}\(\),;\.]/.test(ch))
+ return ret(ch);
+ // start of a number value?
+ else if (/\d/.test(ch)) {
+ stream.eatWhile(/[\w\.]/);
+ return ret("number", "number");
+ }
+ // multi line comment or simple operator?
+ else if (ch == "/") {
+ if (stream.eat("*")) {
+ return chain(stream, state, tokenComment);
+ }
+ else {
+ stream.eatWhile(isOperatorChar);
+ return ret("operator", "operator");
+ }
+ }
+ // single line comment or simple operator?
+ else if (ch == "-") {
+ if (stream.eat("-")) {
+ stream.skipToEnd();
+ return ret("comment", "comment");
+ }
+ else {
+ stream.eatWhile(isOperatorChar);
+ return ret("operator", "operator");
+ }
+ }
+ // pl/sql variable?
+ else if (ch == "@" || ch == "$") {
+ stream.eatWhile(/[\w\d\$_]/);
+ return ret("word", "variable");
+ }
+ // is it a operator?
+ else if (isOperatorChar.test(ch)) {
+ stream.eatWhile(isOperatorChar);
+ return ret("operator", "operator");
+ }
+ else {
+ // get the whole word
+ stream.eatWhile(/[\w\$_]/);
+ // is it one of the listed keywords?
+ if (keywords && keywords.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "keyword");
+ // is it one of the listed functions?
+ if (functions && functions.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "builtin");
+ // is it one of the listed types?
+ if (types && types.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "variable-2");
+ // is it one of the listed sqlplus keywords?
+ if (sqlplus && sqlplus.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "variable-3");
+ // default: just a "variable"
+ return ret("word", "variable");
+ }
+ }
+
+ function tokenString(quote) {
+ return function(stream, state) {
+ var escaped = false, next, end = false;
+ while ((next = stream.next()) != null) {
+ if (next == quote && !escaped) {end = true; break;}
+ escaped = !escaped && next == "\\";
+ }
+ if (end || !(escaped || multiLineStrings))
+ state.tokenize = tokenBase;
+ return ret("string", "plsql-string");
+ };
+ }
+
+ function tokenComment(stream, state) {
+ var maybeEnd = false, ch;
+ while (ch = stream.next()) {
+ if (ch == "/" && maybeEnd) {
+ state.tokenize = tokenBase;
+ break;
+ }
+ maybeEnd = (ch == "*");
+ }
+ return ret("comment", "plsql-comment");
+ }
+
+ // Interface
+
+ return {
+ startState: function(basecolumn) {
+ return {
+ tokenize: tokenBase,
+ startOfLine: true
+ };
+ },
+
+ token: function(stream, state) {
+ if (stream.eatSpace()) return null;
+ var style = state.tokenize(stream, state);
+ return style;
+ }
+ };
+});
+
+(function() {
+ function keywords(str) {
+ var obj = {}, words = str.split(" ");
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
+ return obj;
+ }
+ var cKeywords = "abort accept access add all alter and any array arraylen as asc assert assign at attributes audit " +
+ "authorization avg " +
+ "base_table begin between binary_integer body boolean by " +
+ "case cast char char_base check close cluster clusters colauth column comment commit compress connect " +
+ "connected constant constraint crash create current currval cursor " +
+ "data_base database date dba deallocate debugoff debugon decimal declare default definition delay delete " +
+ "desc digits dispose distinct do drop " +
+ "else elsif enable end entry escape exception exception_init exchange exclusive exists exit external " +
+ "fast fetch file for force form from function " +
+ "generic goto grant group " +
+ "having " +
+ "identified if immediate in increment index indexes indicator initial initrans insert interface intersect " +
+ "into is " +
+ "key " +
+ "level library like limited local lock log logging long loop " +
+ "master maxextents maxtrans member minextents minus mislabel mode modify multiset " +
+ "new next no noaudit nocompress nologging noparallel not nowait number_base " +
+ "object of off offline on online only open option or order out " +
+ "package parallel partition pctfree pctincrease pctused pls_integer positive positiven pragma primary prior " +
+ "private privileges procedure public " +
+ "raise range raw read rebuild record ref references refresh release rename replace resource restrict return " +
+ "returning reverse revoke rollback row rowid rowlabel rownum rows run " +
+ "savepoint schema segment select separate session set share snapshot some space split sql start statement " +
+ "storage subtype successful synonym " +
+ "tabauth table tables tablespace task terminate then to trigger truncate type " +
+ "union unique unlimited unrecoverable unusable update use using " +
+ "validate value values variable view views " +
+ "when whenever where while with work";
+
+ var cFunctions = "abs acos add_months ascii asin atan atan2 average " +
+ "bfilename " +
+ "ceil chartorowid chr concat convert cos cosh count " +
+ "decode deref dual dump dup_val_on_index " +
+ "empty error exp " +
+ "false floor found " +
+ "glb greatest " +
+ "hextoraw " +
+ "initcap instr instrb isopen " +
+ "last_day least lenght lenghtb ln lower lpad ltrim lub " +
+ "make_ref max min mod months_between " +
+ "new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower " +
+ "nls_sort nls_upper nlssort no_data_found notfound null nvl " +
+ "others " +
+ "power " +
+ "rawtohex reftohex round rowcount rowidtochar rpad rtrim " +
+ "sign sin sinh soundex sqlcode sqlerrm sqrt stddev substr substrb sum sysdate " +
+ "tan tanh to_char to_date to_label to_multi_byte to_number to_single_byte translate true trunc " +
+ "uid upper user userenv " +
+ "variance vsize";
+
+ var cTypes = "bfile blob " +
+ "character clob " +
+ "dec " +
+ "float " +
+ "int integer " +
+ "mlslabel " +
+ "natural naturaln nchar nclob number numeric nvarchar2 " +
+ "real rowtype " +
+ "signtype smallint string " +
+ "varchar varchar2";
+
+ var cSqlplus = "appinfo arraysize autocommit autoprint autorecovery autotrace " +
+ "blockterminator break btitle " +
+ "cmdsep colsep compatibility compute concat copycommit copytypecheck " +
+ "define describe " +
+ "echo editfile embedded escape exec execute " +
+ "feedback flagger flush " +
+ "heading headsep " +
+ "instance " +
+ "linesize lno loboffset logsource long longchunksize " +
+ "markup " +
+ "native newpage numformat numwidth " +
+ "pagesize pause pno " +
+ "recsep recsepchar release repfooter repheader " +
+ "serveroutput shiftinout show showmode size spool sqlblanklines sqlcase sqlcode sqlcontinue sqlnumber " +
+ "sqlpluscompatibility sqlprefix sqlprompt sqlterminator suffix " +
+ "tab term termout time timing trimout trimspool ttitle " +
+ "underline " +
+ "verify version " +
+ "wrap";
+
+ CodeMirror.defineMIME("text/x-plsql", {
+ name: "plsql",
+ keywords: keywords(cKeywords),
+ functions: keywords(cFunctions),
+ types: keywords(cTypes),
+ sqlplus: keywords(cSqlplus)
+ });
+}());
diff --git a/codemirror-2.36/mode/properties/index.html b/codemirror-2.36/mode/properties/index.html
new file mode 100755
index 00000000..e21e02ab
--- /dev/null
+++ b/codemirror-2.36/mode/properties/index.html
@@ -0,0 +1,41 @@
+
+
+
MIME types defined: text/x-properties
,
+ text/x-ini
.
MIME types defined: text/x-python
.
MIME types defined: text/x-rsrc
.
Development of the CodeMirror R mode was kindly sponsored + by Ubalo, who hold + the license.
+ + + diff --git a/codemirror-2.36/mode/r/r.js b/codemirror-2.36/mode/r/r.js new file mode 100644 index 00000000..53647f23 --- /dev/null +++ b/codemirror-2.36/mode/r/r.js @@ -0,0 +1,141 @@ +CodeMirror.defineMode("r", function(config) { + function wordObj(str) { + var words = str.split(" "), res = {}; + for (var i = 0; i < words.length; ++i) res[words[i]] = true; + return res; + } + var atoms = wordObj("NULL NA Inf NaN NA_integer_ NA_real_ NA_complex_ NA_character_"); + var builtins = wordObj("list quote bquote eval return call parse deparse"); + var keywords = wordObj("if else repeat while function for in next break"); + var blockkeywords = wordObj("if else repeat while function for"); + var opChars = /[+\-*\/^<>=!&|~$:]/; + var curPunc; + + function tokenBase(stream, state) { + curPunc = null; + var ch = stream.next(); + if (ch == "#") { + stream.skipToEnd(); + return "comment"; + } else if (ch == "0" && stream.eat("x")) { + stream.eatWhile(/[\da-f]/i); + return "number"; + } else if (ch == "." && stream.eat(/\d/)) { + stream.match(/\d*(?:e[+\-]?\d+)?/); + return "number"; + } else if (/\d/.test(ch)) { + stream.match(/\d*(?:\.\d+)?(?:e[+\-]\d+)?L?/); + return "number"; + } else if (ch == "'" || ch == '"') { + state.tokenize = tokenString(ch); + return "string"; + } else if (ch == "." && stream.match(/.[.\d]+/)) { + return "keyword"; + } else if (/[\w\.]/.test(ch) && ch != "_") { + stream.eatWhile(/[\w\.]/); + var word = stream.current(); + if (atoms.propertyIsEnumerable(word)) return "atom"; + if (keywords.propertyIsEnumerable(word)) { + if (blockkeywords.propertyIsEnumerable(word)) curPunc = "block"; + return "keyword"; + } + if (builtins.propertyIsEnumerable(word)) return "builtin"; + return "variable"; + } else if (ch == "%") { + if (stream.skipTo("%")) stream.next(); + return "variable-2"; + } else if (ch == "<" && stream.eat("-")) { + return "arrow"; + } else if (ch == "=" && state.ctx.argList) { + return "arg-is"; + } else if (opChars.test(ch)) { + if (ch == "$") return "dollar"; + stream.eatWhile(opChars); + return "operator"; + } else if (/[\(\){}\[\];]/.test(ch)) { + curPunc = ch; + if (ch == ";") return "semi"; + return null; + } else { + return null; + } + } + + function tokenString(quote) { + return function(stream, state) { + if (stream.eat("\\")) { + var ch = stream.next(); + if (ch == "x") stream.match(/^[a-f0-9]{2}/i); + else if ((ch == "u" || ch == "U") && stream.eat("{") && stream.skipTo("}")) stream.next(); + else if (ch == "u") stream.match(/^[a-f0-9]{4}/i); + else if (ch == "U") stream.match(/^[a-f0-9]{8}/i); + else if (/[0-7]/.test(ch)) stream.match(/^[0-7]{1,2}/); + return "string-2"; + } else { + var next; + while ((next = stream.next()) != null) { + if (next == quote) { state.tokenize = tokenBase; break; } + if (next == "\\") { stream.backUp(1); break; } + } + return "string"; + } + }; + } + + function push(state, type, stream) { + state.ctx = {type: type, + indent: state.indent, + align: null, + column: stream.column(), + prev: state.ctx}; + } + function pop(state) { + state.indent = state.ctx.indent; + state.ctx = state.ctx.prev; + } + + return { + startState: function(base) { + return {tokenize: tokenBase, + ctx: {type: "top", + indent: -config.indentUnit, + align: false}, + indent: 0, + afterIdent: false}; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (state.ctx.align == null) state.ctx.align = false; + state.indent = stream.indentation(); + } + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + if (style != "comment" && state.ctx.align == null) state.ctx.align = true; + + var ctype = state.ctx.type; + if ((curPunc == ";" || curPunc == "{" || curPunc == "}") && ctype == "block") pop(state); + if (curPunc == "{") push(state, "}", stream); + else if (curPunc == "(") { + push(state, ")", stream); + if (state.afterIdent) state.ctx.argList = true; + } + else if (curPunc == "[") push(state, "]", stream); + else if (curPunc == "block") push(state, "block", stream); + else if (curPunc == ctype) pop(state); + state.afterIdent = style == "variable" || style == "keyword"; + return style; + }, + + indent: function(state, textAfter) { + if (state.tokenize != tokenBase) return 0; + var firstChar = textAfter && textAfter.charAt(0), ctx = state.ctx, + closing = firstChar == ctx.type; + if (ctx.type == "block") return ctx.indent + (firstChar == "{" ? 0 : config.indentUnit); + else if (ctx.align) return ctx.column + (closing ? 0 : 1); + else return ctx.indent + (closing ? 0 : config.indentUnit); + } + }; +}); + +CodeMirror.defineMIME("text/x-rsrc", "r"); diff --git a/codemirror-2.36/mode/rpm/changes/changes.js b/codemirror-2.36/mode/rpm/changes/changes.js new file mode 100644 index 00000000..cb45f9e5 --- /dev/null +++ b/codemirror-2.36/mode/rpm/changes/changes.js @@ -0,0 +1,19 @@ +CodeMirror.defineMode("changes", function(config, modeConfig) { + var headerSeperator = /^-+$/; + var headerLine = /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ?\d{1,2} \d{2}:\d{2}(:\d{2})? [A-Z]{3,4} \d{4} - /; + var simpleEmail = /^[\w+.-]+@[\w.-]+/; + + return { + token: function(stream) { + if (stream.sol()) { + if (stream.match(headerSeperator)) { return 'tag'; } + if (stream.match(headerLine)) { return 'tag'; } + } + if (stream.match(simpleEmail)) { return 'string'; } + stream.next(); + return null; + } + }; +}); + +CodeMirror.defineMIME("text/x-rpm-changes", "changes"); diff --git a/codemirror-2.36/mode/rpm/changes/index.html b/codemirror-2.36/mode/rpm/changes/index.html new file mode 100644 index 00000000..3f3dccc8 --- /dev/null +++ b/codemirror-2.36/mode/rpm/changes/index.html @@ -0,0 +1,54 @@ + + + + +MIME types defined: text/x-rpm-changes
.
MIME types defined: text/x-rpm-spec
.
The reStructuredText mode supports one configuration parameter:
+verbatim (string)
If python
mode is available,
+ it will be used for highlighting blocks containing Python/IPython terminal
+ sessions (blocks starting with >>>
(for Python) or
+ In [num]:
(for IPython).
+
+
MIME types defined: text/x-rst
.
MIME types defined: text/x-ruby
.
Development of the CodeMirror Ruby mode was kindly sponsored + by Ubalo, who hold + the license.
+ + + diff --git a/codemirror-2.36/mode/ruby/ruby.js b/codemirror-2.36/mode/ruby/ruby.js new file mode 100644 index 00000000..74ed7b96 --- /dev/null +++ b/codemirror-2.36/mode/ruby/ruby.js @@ -0,0 +1,195 @@ +CodeMirror.defineMode("ruby", function(config, parserConfig) { + function wordObj(words) { + var o = {}; + for (var i = 0, e = words.length; i < e; ++i) o[words[i]] = true; + return o; + } + var keywords = wordObj([ + "alias", "and", "BEGIN", "begin", "break", "case", "class", "def", "defined?", "do", "else", + "elsif", "END", "end", "ensure", "false", "for", "if", "in", "module", "next", "not", "or", + "redo", "rescue", "retry", "return", "self", "super", "then", "true", "undef", "unless", + "until", "when", "while", "yield", "nil", "raise", "throw", "catch", "fail", "loop", "callcc", + "caller", "lambda", "proc", "public", "protected", "private", "require", "load", + "require_relative", "extend", "autoload" + ]); + var indentWords = wordObj(["def", "class", "case", "for", "while", "do", "module", "then", + "catch", "loop", "proc", "begin"]); + var dedentWords = wordObj(["end", "until"]); + var matching = {"[": "]", "{": "}", "(": ")"}; + var curPunc; + + function chain(newtok, stream, state) { + state.tokenize.push(newtok); + return newtok(stream, state); + } + + function tokenBase(stream, state) { + curPunc = null; + if (stream.sol() && stream.match("=begin") && stream.eol()) { + state.tokenize.push(readBlockComment); + return "comment"; + } + if (stream.eatSpace()) return null; + var ch = stream.next(), m; + if (ch == "`" || ch == "'" || ch == '"' || + (ch == "/" && !stream.eol() && stream.peek() != " ")) { + return chain(readQuoted(ch, "string", ch == '"' || ch == "`"), stream, state); + } else if (ch == "%") { + var style, embed = false; + if (stream.eat("s")) style = "atom"; + else if (stream.eat(/[WQ]/)) { style = "string"; embed = true; } + else if (stream.eat(/[wxqr]/)) style = "string"; + var delim = stream.eat(/[^\w\s]/); + if (!delim) return "operator"; + if (matching.propertyIsEnumerable(delim)) delim = matching[delim]; + return chain(readQuoted(delim, style, embed, true), stream, state); + } else if (ch == "#") { + stream.skipToEnd(); + return "comment"; + } else if (ch == "<" && (m = stream.match(/^<-?[\`\"\']?([a-zA-Z_?]\w*)[\`\"\']?(?:;|$)/))) { + return chain(readHereDoc(m[1]), stream, state); + } else if (ch == "0") { + if (stream.eat("x")) stream.eatWhile(/[\da-fA-F]/); + else if (stream.eat("b")) stream.eatWhile(/[01]/); + else stream.eatWhile(/[0-7]/); + return "number"; + } else if (/\d/.test(ch)) { + stream.match(/^[\d_]*(?:\.[\d_]+)?(?:[eE][+\-]?[\d_]+)?/); + return "number"; + } else if (ch == "?") { + while (stream.match(/^\\[CM]-/)) {} + if (stream.eat("\\")) stream.eatWhile(/\w/); + else stream.next(); + return "string"; + } else if (ch == ":") { + if (stream.eat("'")) return chain(readQuoted("'", "atom", false), stream, state); + if (stream.eat('"')) return chain(readQuoted('"', "atom", true), stream, state); + stream.eatWhile(/[\w\?]/); + return "atom"; + } else if (ch == "@") { + stream.eat("@"); + stream.eatWhile(/[\w\?]/); + return "variable-2"; + } else if (ch == "$") { + stream.next(); + stream.eatWhile(/[\w\?]/); + return "variable-3"; + } else if (/\w/.test(ch)) { + stream.eatWhile(/[\w\?]/); + if (stream.eat(":")) return "atom"; + return "ident"; + } else if (ch == "|" && (state.varList || state.lastTok == "{" || state.lastTok == "do")) { + curPunc = "|"; + return null; + } else if (/[\(\)\[\]{}\\;]/.test(ch)) { + curPunc = ch; + return null; + } else if (ch == "-" && stream.eat(">")) { + return "arrow"; + } else if (/[=+\-\/*:\.^%<>~|]/.test(ch)) { + stream.eatWhile(/[=+\-\/*:\.^%<>~|]/); + return "operator"; + } else { + return null; + } + } + + function tokenBaseUntilBrace() { + var depth = 1; + return function(stream, state) { + if (stream.peek() == "}") { + depth--; + if (depth == 0) { + state.tokenize.pop(); + return state.tokenize[state.tokenize.length-1](stream, state); + } + } else if (stream.peek() == "{") { + depth++; + } + return tokenBase(stream, state); + }; + } + function readQuoted(quote, style, embed, unescaped) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && (unescaped || !escaped)) { + state.tokenize.pop(); + break; + } + if (embed && ch == "#" && !escaped && stream.eat("{")) { + state.tokenize.push(tokenBaseUntilBrace(arguments.callee)); + break; + } + escaped = !escaped && ch == "\\"; + } + return style; + }; + } + function readHereDoc(phrase) { + return function(stream, state) { + if (stream.match(phrase)) state.tokenize.pop(); + else stream.skipToEnd(); + return "string"; + }; + } + function readBlockComment(stream, state) { + if (stream.sol() && stream.match("=end") && stream.eol()) + state.tokenize.pop(); + stream.skipToEnd(); + return "comment"; + } + + return { + startState: function() { + return {tokenize: [tokenBase], + indented: 0, + context: {type: "top", indented: -config.indentUnit}, + continuedLine: false, + lastTok: null, + varList: false}; + }, + + token: function(stream, state) { + if (stream.sol()) state.indented = stream.indentation(); + var style = state.tokenize[state.tokenize.length-1](stream, state), kwtype; + if (style == "ident") { + var word = stream.current(); + style = keywords.propertyIsEnumerable(stream.current()) ? "keyword" + : /^[A-Z]/.test(word) ? "tag" + : (state.lastTok == "def" || state.lastTok == "class" || state.varList) ? "def" + : "variable"; + if (indentWords.propertyIsEnumerable(word)) kwtype = "indent"; + else if (dedentWords.propertyIsEnumerable(word)) kwtype = "dedent"; + else if ((word == "if" || word == "unless") && stream.column() == stream.indentation()) + kwtype = "indent"; + } + if (curPunc || (style && style != "comment")) state.lastTok = word || curPunc || style; + if (curPunc == "|") state.varList = !state.varList; + + if (kwtype == "indent" || /[\(\[\{]/.test(curPunc)) + state.context = {prev: state.context, type: curPunc || style, indented: state.indented}; + else if ((kwtype == "dedent" || /[\)\]\}]/.test(curPunc)) && state.context.prev) + state.context = state.context.prev; + + if (stream.eol()) + state.continuedLine = (curPunc == "\\" || style == "operator"); + return style; + }, + + indent: function(state, textAfter) { + if (state.tokenize[state.tokenize.length-1] != tokenBase) return 0; + var firstChar = textAfter && textAfter.charAt(0); + var ct = state.context; + var closing = ct.type == matching[firstChar] || + ct.type == "keyword" && /^(?:end|until|else|elsif|when|rescue)\b/.test(textAfter); + return ct.indented + (closing ? 0 : config.indentUnit) + + (state.continuedLine ? config.indentUnit : 0); + }, + electricChars: "}de" // enD and rescuE + + }; +}); + +CodeMirror.defineMIME("text/x-ruby", "ruby"); + diff --git a/codemirror-2.36/mode/rust/index.html b/codemirror-2.36/mode/rust/index.html new file mode 100644 index 00000000..b3bbb1f8 --- /dev/null +++ b/codemirror-2.36/mode/rust/index.html @@ -0,0 +1,49 @@ + + + + +MIME types defined: text/x-rustsrc
.
MIME types defined: text/x-scheme
.
MIME types defined: text/x-sh
.
MIME types defined: application/sieve
.
Simple Smalltalk mode.
+ +MIME types defined: text/x-stsrc
.
A plain text/Smarty mode which allows for custom delimiter tags (defaults to { and }).
+ +MIME types defined: text/x-smarty
MIME types defined: application/x-sparql-query
.
MIME types defined: text/x-stex
.
Parsing/Highlighting Tests: normal, verbose.
+ + + diff --git a/codemirror-2.36/mode/stex/stex.js b/codemirror-2.36/mode/stex/stex.js new file mode 100644 index 00000000..100854da --- /dev/null +++ b/codemirror-2.36/mode/stex/stex.js @@ -0,0 +1,182 @@ +/* + * Author: Constantin Jucovschi (c.jucovschi@jacobs-university.de) + * Licence: MIT + */ + +CodeMirror.defineMode("stex", function(cmCfg, modeCfg) +{ + function pushCommand(state, command) { + state.cmdState.push(command); + } + + function peekCommand(state) { + if (state.cmdState.length>0) + return state.cmdState[state.cmdState.length-1]; + else + return null; + } + + function popCommand(state) { + if (state.cmdState.length>0) { + var plug = state.cmdState.pop(); + plug.closeBracket(); + } + } + + function applyMostPowerful(state) { + var context = state.cmdState; + for (var i = context.length - 1; i >= 0; i--) { + var plug = context[i]; + if (plug.name=="DEFAULT") + continue; + return plug.styleIdentifier(); + } + return null; + } + + function addPluginPattern(pluginName, cmdStyle, brackets, styles) { + return function () { + this.name=pluginName; + this.bracketNo = 0; + this.style=cmdStyle; + this.styles = styles; + this.brackets = brackets; + + this.styleIdentifier = function(content) { + if (this.bracketNo<=this.styles.length) + return this.styles[this.bracketNo-1]; + else + return null; + }; + this.openBracket = function(content) { + this.bracketNo++; + return "bracket"; + }; + this.closeBracket = function(content) { + }; + }; + } + + var plugins = new Array(); + + plugins["importmodule"] = addPluginPattern("importmodule", "tag", "{[", ["string", "builtin"]); + plugins["documentclass"] = addPluginPattern("documentclass", "tag", "{[", ["", "atom"]); + plugins["usepackage"] = addPluginPattern("documentclass", "tag", "[", ["atom"]); + plugins["begin"] = addPluginPattern("documentclass", "tag", "[", ["atom"]); + plugins["end"] = addPluginPattern("documentclass", "tag", "[", ["atom"]); + + plugins["DEFAULT"] = function () { + this.name="DEFAULT"; + this.style="tag"; + + this.styleIdentifier = function(content) { + }; + this.openBracket = function(content) { + }; + this.closeBracket = function(content) { + }; + }; + + function setState(state, f) { + state.f = f; + } + + function normal(source, state) { + if (source.match(/^\\[a-zA-Z@]+/)) { + var cmdName = source.current(); + cmdName = cmdName.substr(1, cmdName.length-1); + var plug; + if (plugins.hasOwnProperty(cmdName)) { + plug = plugins[cmdName]; + } else { + plug = plugins["DEFAULT"]; + } + plug = new plug(); + pushCommand(state, plug); + setState(state, beginParams); + return plug.style; + } + + // escape characters + if (source.match(/^\\[$&%#{}_]/)) { + return "tag"; + } + + // white space control characters + if (source.match(/^\\[,;!\/]/)) { + return "tag"; + } + + var ch = source.next(); + if (ch == "%") { + // special case: % at end of its own line; stay in same state + if (!source.eol()) { + setState(state, inCComment); + } + return "comment"; + } + else if (ch=='}' || ch==']') { + plug = peekCommand(state); + if (plug) { + plug.closeBracket(ch); + setState(state, beginParams); + } else + return "error"; + return "bracket"; + } else if (ch=='{' || ch=='[') { + plug = plugins["DEFAULT"]; + plug = new plug(); + pushCommand(state, plug); + return "bracket"; + } + else if (/\d/.test(ch)) { + source.eatWhile(/[\w.%]/); + return "atom"; + } + else { + source.eatWhile(/[\w-_]/); + return applyMostPowerful(state); + } + } + + function inCComment(source, state) { + source.skipToEnd(); + setState(state, normal); + return "comment"; + } + + function beginParams(source, state) { + var ch = source.peek(); + if (ch == '{' || ch == '[') { + var lastPlug = peekCommand(state); + var style = lastPlug.openBracket(ch); + source.eat(ch); + setState(state, normal); + return "bracket"; + } + if (/[ \t\r]/.test(ch)) { + source.eat(ch); + return null; + } + setState(state, normal); + lastPlug = peekCommand(state); + if (lastPlug) { + popCommand(state); + } + return normal(source, state); + } + + return { + startState: function() { return { f:normal, cmdState:[] }; }, + copyState: function(s) { return { f: s.f, cmdState: s.cmdState.slice(0, s.cmdState.length) }; }, + + token: function(stream, state) { + var t = state.f(stream, state); + var w = stream.current(); + return t; + } + }; +}); + +CodeMirror.defineMIME("text/x-stex", "stex"); +CodeMirror.defineMIME("text/x-latex", "stex"); diff --git a/codemirror-2.36/mode/stex/test.js b/codemirror-2.36/mode/stex/test.js new file mode 100644 index 00000000..c5a34f3d --- /dev/null +++ b/codemirror-2.36/mode/stex/test.js @@ -0,0 +1,343 @@ +var MT = ModeTest; +MT.modeName = 'stex'; +MT.modeOptions = {}; + +MT.testMode( + 'word', + 'foo', + [ + null, 'foo' + ] +); + +MT.testMode( + 'twoWords', + 'foo bar', + [ + null, 'foo bar' + ] +); + +MT.testMode( + 'beginEndDocument', + '\\begin{document}\n\\end{document}', + [ + 'tag', '\\begin', + 'bracket', '{', + 'atom', 'document', + 'bracket', '}', + 'tag', '\\end', + 'bracket', '{', + 'atom', 'document', + 'bracket', '}' + ] +); + +MT.testMode( + 'beginEndEquation', + '\\begin{equation}\n E=mc^2\n\\end{equation}', + [ + 'tag', '\\begin', + 'bracket', '{', + 'atom', 'equation', + 'bracket', '}', + null, ' E=mc^2', + 'tag', '\\end', + 'bracket', '{', + 'atom', 'equation', + 'bracket', '}' + ] +); + +MT.testMode( + 'beginModule', + '\\begin{module}[]', + [ + 'tag', '\\begin', + 'bracket', '{', + 'atom', 'module', + 'bracket', '}[]' + ] +); + +MT.testMode( + 'beginModuleId', + '\\begin{module}[id=bbt-size]', + [ + 'tag', '\\begin', + 'bracket', '{', + 'atom', 'module', + 'bracket', '}[', + null, 'id=bbt-size', + 'bracket', ']' + ] +); + +MT.testMode( + 'importModule', + '\\importmodule[b-b-t]{b-b-t}', + [ + 'tag', '\\importmodule', + 'bracket', '[', + 'string', 'b-b-t', + 'bracket', ']{', + 'builtin', 'b-b-t', + 'bracket', '}' + ] +); + +MT.testMode( + 'importModulePath', + '\\importmodule[\\KWARCslides{dmath/en/cardinality}]{card}', + [ + 'tag', '\\importmodule', + 'bracket', '[', + 'tag', '\\KWARCslides', + 'bracket', '{', + 'string', 'dmath/en/cardinality', + 'bracket', '}]{', + 'builtin', 'card', + 'bracket', '}' + ] +); + +MT.testMode( + 'psForPDF', + '\\PSforPDF[1]{#1}', // could treat #1 specially + [ + 'tag', '\\PSforPDF', + 'bracket', '[', + 'atom', '1', + 'bracket', ']{', + null, '#1', + 'bracket', '}' + ] +); + +MT.testMode( + 'comment', + '% foo', + [ + 'comment', '% foo' + ] +); + +MT.testMode( + 'tagComment', + '\\item% bar', + [ + 'tag', '\\item', + 'comment', '% bar' + ] +); + +MT.testMode( + 'commentTag', + ' % \\item', + [ + null, ' ', + 'comment', '% \\item' + ] +); + +MT.testMode( + 'commentLineBreak', + '%\nfoo', + [ + 'comment', '%', + null, 'foo' + ] +); + +MT.testMode( + 'tagErrorCurly', + '\\begin}{', + [ + 'tag', '\\begin', + 'error', '}', + 'bracket', '{' + ] +); + +MT.testMode( + 'tagErrorSquare', + '\\item]{', + [ + 'tag', '\\item', + 'error', ']', + 'bracket', '{' + ] +); + +MT.testMode( + 'commentCurly', + '% }', + [ + 'comment', '% }' + ] +); + +MT.testMode( + 'tagHash', + 'the \\# key', + [ + null, 'the ', + 'tag', '\\#', + null, ' key' + ] +); + +MT.testMode( + 'tagNumber', + 'a \\$5 stetson', + [ + null, 'a ', + 'tag', '\\$', + 'atom', 5, + null, ' stetson' + ] +); + +MT.testMode( + 'tagPercent', + '100\\% beef', + [ + 'atom', '100', + 'tag', '\\%', + null, ' beef' + ] +); + +MT.testMode( + 'tagAmpersand', + 'L \\& N', + [ + null, 'L ', + 'tag', '\\&', + null, ' N' + ] +); + +MT.testMode( + 'tagUnderscore', + 'foo\\_bar', + [ + null, 'foo', + 'tag', '\\_', + null, 'bar' + ] +); + +MT.testMode( + 'tagBracketOpen', + '\\emph{\\{}', + [ + 'tag', '\\emph', + 'bracket', '{', + 'tag', '\\{', + 'bracket', '}' + ] +); + +MT.testMode( + 'tagBracketClose', + '\\emph{\\}}', + [ + 'tag', '\\emph', + 'bracket', '{', + 'tag', '\\}', + 'bracket', '}' + ] +); + +MT.testMode( + 'tagLetterNumber', + 'section \\S1', + [ + null, 'section ', + 'tag', '\\S', + 'atom', '1' + ] +); + +MT.testMode( + 'textTagNumber', + 'para \\P2', + [ + null, 'para ', + 'tag', '\\P', + 'atom', '2' + ] +); + +MT.testMode( + 'thinspace', + 'x\\,y', // thinspace + [ + null, 'x', + 'tag', '\\,', + null, 'y' + ] +); + +MT.testMode( + 'thickspace', + 'x\\;y', // thickspace + [ + null, 'x', + 'tag', '\\;', + null, 'y' + ] +); + +MT.testMode( + 'negativeThinspace', + 'x\\!y', // negative thinspace + [ + null, 'x', + 'tag', '\\!', + null, 'y' + ] +); + +MT.testMode( + 'periodNotSentence', + 'J.\\ L.\\ is', // period not ending a sentence + [ + null, 'J.\\ L.\\ is' + ] +); // maybe could be better + +MT.testMode( + 'periodSentence', + 'X\\@. The', // period ending a sentence + [ + null, 'X', + 'tag', '\\@', + null, '. The' + ] +); + +MT.testMode( + 'italicCorrection', + '{\\em If\\/} I', // italic correction + [ + 'bracket', '{', + 'tag', '\\em', + null, ' If', + 'tag', '\\/', + 'bracket', '}', + null, ' I' + ] +); + +MT.testMode( + 'tagBracket', + '\\newcommand{\\pop}', + [ + 'tag', '\\newcommand', + 'bracket', '{', + 'tag', '\\pop', + 'bracket', '}' + ] +); \ No newline at end of file diff --git a/codemirror-2.36/mode/tiddlywiki/index.html b/codemirror-2.36/mode/tiddlywiki/index.html new file mode 100644 index 00000000..40c2dff5 --- /dev/null +++ b/codemirror-2.36/mode/tiddlywiki/index.html @@ -0,0 +1,141 @@ + + + + +TiddlyWiki mode supports a single configuration.
+ +MIME types defined: text/x-tiddlywiki
.
MIME type defined: text/x-vb
.
MIME types defined: text/vbscript
.
MIME types defined: text/velocity
.
Simple mode that tries to handle Verilog-like languages as well as it
+ can. Takes one configuration parameters: keywords
, an
+ object whose property names are the keywords in the language.
MIME types defined: text/x-verilog
(Verilog code).
The XML mode supports two configuration parameters:
+htmlMode (boolean)
br
) do not require a closing tag.alignCDATA (boolean)
MIME types defined: application/xml
, text/html
.
MIME types defined: application/xquery
.
Development of the CodeMirror XQuery mode was sponsored by + MarkLogic and developed by + Mike Brevoort. +
+ + + diff --git a/codemirror-2.36/mode/xquery/test/index.html b/codemirror-2.36/mode/xquery/test/index.html new file mode 100644 index 00000000..ba82e54f --- /dev/null +++ b/codemirror-2.36/mode/xquery/test/index.html @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + +hello world
'); + var editor = CodeMirror.fromTextArea($("#editor")[0]); + var result = $(".CodeMirror-lines div div pre")[0].innerHTML; + + equal(result, expected); + $("#editor").html(""); + }); + }); \ No newline at end of file diff --git a/codemirror-2.36/mode/xquery/test/testNamespaces.js b/codemirror-2.36/mode/xquery/test/testNamespaces.js new file mode 100644 index 00000000..4efea63e --- /dev/null +++ b/codemirror-2.36/mode/xquery/test/testNamespaces.js @@ -0,0 +1,91 @@ +$(document).ready(function(){ + module("test namespaces"); + +// -------------------------------------------------------------------------------- +// this test is based on this: +//http://mbrevoort.github.com/CodeMirror2/#!exprSeqTypes/PrologExpr/VariableProlog/ExternalVariablesWith/K2-ExternalVariablesWith-10.xq +// -------------------------------------------------------------------------------- + test("test namespaced variable", function() { + expect(1); + + var input = 'declare namespace e = "http://example.com/ANamespace";\ +declare variable $e:exampleComThisVarIsNotRecognized as element(*) external;'; + + var expected = 'declare namespace e = "http://example.com/ANamespace";declare variable $e:exampleComThisVarIsNotRecognized as element(*) external;'; + + $("#sandbox").html(''); + var editor = CodeMirror.fromTextArea($("#editor")[0]); + var result = $(".CodeMirror-lines div div pre")[0].innerHTML; + + equal(result, expected); + $("#editor").html(""); + }); + + +// -------------------------------------------------------------------------------- +// this test is based on: +// http://mbrevoort.github.com/CodeMirror2/#!Basics/EQNames/eqname-002.xq +// -------------------------------------------------------------------------------- + test("test EQName variable", function() { + expect(1); + + var input = 'declare variable $"http://www.example.com/ns/my":var := 12;\ +MIME types defined: text/x-yaml
.
MIME type defined: text/x-z80
.
A limited set of programmatic sanity tests for CodeMirror.
+ +Please enable JavaScript...
+ + + + + + + + + + + + + + + + + + diff --git a/codemirror-2.36/test/lint/lint.js b/codemirror-2.36/test/lint/lint.js new file mode 100644 index 00000000..1a3125ce --- /dev/null +++ b/codemirror-2.36/test/lint/lint.js @@ -0,0 +1,120 @@ +/* + Simple linter, based on UglifyJS's [1] parse-js module + + All of the existing linters either cramp my style or have huge + dependencies (Closure). So here's a very simple, non-invasive one + that only spots + + - missing semicolons and trailing commas + - variables or properties that are reserved words + - assigning to a variable you didn't declare + + [1]: https://github.com/mishoo/UglifyJS/ +*/ + +var fs = require("fs"), parse_js = require("./parse-js").parse; + +var reserved = {}; +"break case catch continue debugger default delete do else false finally for function if in\ + instanceof new null return switch throw true try typeof var void while with abstract enum\ + int short boolean export interface static byte extends long super char final native\ + synchonized class float package throws const goto private transient implements protected\ + volatile double import public const".split(" ").forEach(function(word) { reserved[word] = true; }); + +function checkVariable(scope, name, pos) { + while (scope) { + if (scope.cur.hasOwnProperty(name)) return; + scope = scope.prev; + } + fail("Accidental global: " + name, pos); +} +function checkProperty(name, pos) { + if (reserved.hasOwnProperty(name)) { + fail("Using a keyword or reserved word as a property: " + name, pos); + } +} + +function walk(ast, scope) { + var tp = ast[0]; + if (typeof tp != "string") tp = tp.name; + function sub(ast) { if (ast) walk(ast, scope); } + function subn(array) { if (array) array.forEach(sub); } + if (tp == "block" || tp == "splice" || tp == "toplevel" || tp == "array") { + subn(ast[1]); + } else if (tp == "var" || tp == "const") { + ast[1].forEach(function(def) { scope.cur[def[0]] = true; if (def[1]) sub(def[1]); }); + } else if (tp == "try") { + subn(ast[1]); + if (ast[2]) { scope.cur[ast[2][0]] = true; subn(ast[2][1]); } + subn(ast[3]); + } else if (tp == "throw" || tp == "return" || tp == "dot" || tp == "stat") { + sub(ast[1]); + } else if (tp == "dot") { + sub(ast[1]); + checkProperty(ast[2], ast[0]); + } else if (tp == "new" || tp == "call") { + sub(ast[1]); subn(ast[2]); + } else if (tp == "switch") { + sub(ast[1]); + ast[2].forEach(function(part) { sub(part[0]); subn(part[1]); }); + } else if (tp == "conditional" || tp == "if" || tp == "for" || tp == "for-in") { + sub(ast[1]); sub(ast[2]); sub(ast[3]); sub(ast[4]); + } else if (tp == "assign") { + if (ast[2][0].name == "name") checkVariable(scope, ast[2][1], ast[2][0]); + sub(ast[2]); sub(ast[3]); + } else if (tp == "function" || tp == "defun") { + if (tp == "defun") scope.cur[ast[1]] = true; + var nscope = {prev: scope, cur: {}}; + ast[2].forEach(function(arg) { nscope.cur[arg] = true; }); + ast[3].forEach(function(ast) { walk(ast, nscope); }); + } else if (tp == "while" || tp == "do" || tp == "sub" || tp == "with") { + sub(ast[1]); sub(ast[2]); + } else if (tp == "binary" || tp == "unary-prefix" || tp == "unary-postfix" || tp == "label") { + if (/\+\+|--/.test(ast[1]) && ast[2][0].name == "name") checkVariable(scope, ast[2][1], ast[2][0]); + sub(ast[2]); sub(ast[3]); + } else if (tp == "object") { + ast[1].forEach(function(prop) { + if (prop.type != "string") checkProperty(prop[0], ast[0]); + sub(prop[1]); sub(prop[2]); + }); + } else if (tp == "seq") { + subn(ast.slice(1)); + } else if (tp == "name") { + if (reserved.hasOwnProperty(ast[1]) && !/^(?:null|true|false)$/.test(ast[1])) + fail("Using reserved word as variable name: " + ast[1], ast[0]); + } +} + +var failed = false, curFile; +function fail(msg, pos) { + if (typeof pos == "object") pos = pos.start.line + 1; + console.log(curFile + ": " + msg + (typeof pos == "number" ? " (" + pos + ")" : "")); + failed = true; +} + +function checkFile(fileName) { + curFile = fileName.match(/[^\/+]*\.js$/)[0]; + var file = fs.readFileSync(fileName, "utf8"); + var badChar = file.match(/[\x00-\x08\x0b\x0c\x0e-\x19\uFEFF]/); + if (badChar) fail("Undesirable character " + badChar[0].charCodeAt(0) + " at position " + badChar.index); + if (/^#!/.test(file)) file = file.slice(file.indexOf("\n") + 1); + try { + var parsed = parse_js(file, true, true); + } catch(e) { + fail(e.message, e.line); + return; + } + walk(parsed, {prev: null, cur: {}}); +} + +function checkDir(dir) { + fs.readdirSync(dir).forEach(function(file) { + var fname = dir + "/" + file; + if (/\.js$/.test(file)) checkFile(fname); + else if (fs.lstatSync(fname).isDirectory()) checkDir(fname); + }); +} + +exports.checkDir = checkDir; +exports.checkFile = checkFile; +exports.success = function() { return !failed; }; diff --git a/codemirror-2.36/test/lint/parse-js.js b/codemirror-2.36/test/lint/parse-js.js new file mode 100644 index 00000000..c165a273 --- /dev/null +++ b/codemirror-2.36/test/lint/parse-js.js @@ -0,0 +1,1372 @@ +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + + This version is suitable for Node.js. With minimal changes (the + exports stuff) it should work on any JS platform. + + This file contains the tokenizer/parser. It is a port to JavaScript + of parse-js [1], a JavaScript parser library written in Common Lisp + by Marijn Haverbeke. Thank you Marijn! + + [1] http://marijn.haverbeke.nl/parse-js/ + + Exported functions: + + - tokenizer(code) -- returns a function. Call the returned + function to fetch the next token. + + - parse(code) -- returns an AST of the given JavaScript code. + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon +' + ModeTest.htmlEscape(text) + ''; + s += '
' + ModeTest.htmlEscape(text) + ''; + s += '
' + + '' + + ModeTest.htmlEscape(token[1]).replace(/ /g,'·') + + '' + + ' | '; + } + s += '
' + token[0] + ' | '; + } + s += '