Commit ded1e4830a9156e65484fb771a80d3f9312eeadb
1 parent
f5d14a87
Exists in
master
and in
7 other branches
Inclusão da biblioteca codemirror em i3geo/pacotes
Showing
363 changed files
with
77180 additions
and
0 deletions
Show diff stats
Too many changes.
To preserve performance only 100 of 363 files displayed.
| ... | ... | @@ -0,0 +1,381 @@ |
| 1 | +List of CodeMirror contributors. Updated before every release. | |
| 2 | + | |
| 3 | +4r2r | |
| 4 | +Aaron Brooks | |
| 5 | +Abe Fettig | |
| 6 | +Adam Ahmed | |
| 7 | +Adam King | |
| 8 | +adanlobato | |
| 9 | +Adán Lobato | |
| 10 | +Adrian Aichner | |
| 11 | +aeroson | |
| 12 | +Ahmad Amireh | |
| 13 | +Ahmad M. Zawawi | |
| 14 | +ahoward | |
| 15 | +Akeksandr Motsjonov | |
| 16 | +Alberto González Palomo | |
| 17 | +Alberto Pose | |
| 18 | +Albert Xing | |
| 19 | +Alexander Pavlov | |
| 20 | +Alexander Schepanovski | |
| 21 | +Alexander Shvets | |
| 22 | +Alexander Solovyov | |
| 23 | +Alexandre Bique | |
| 24 | +alexey-k | |
| 25 | +Alex Piggott | |
| 26 | +Amsul | |
| 27 | +amuntean | |
| 28 | +Amy | |
| 29 | +Ananya Sen | |
| 30 | +anaran | |
| 31 | +AndersMad | |
| 32 | +Anders Nawroth | |
| 33 | +Anderson Mesquita | |
| 34 | +Andreas Reischuck | |
| 35 | +Andre von Houck | |
| 36 | +Andrey Fedorov | |
| 37 | +Andrey Lushnikov | |
| 38 | +Andy Joslin | |
| 39 | +Andy Kimball | |
| 40 | +Andy Li | |
| 41 | +angelozerr | |
| 42 | +angelo.zerr@gmail.com | |
| 43 | +Ankit Ahuja | |
| 44 | +Ansel Santosa | |
| 45 | +Anthony Grimes | |
| 46 | +Anton Kovalyov | |
| 47 | +areos | |
| 48 | +as3boyan | |
| 49 | +AtomicPages LLC | |
| 50 | +Atul Bhouraskar | |
| 51 | +Aurelian Oancea | |
| 52 | +Bastian Müller | |
| 53 | +Bem Jones-Bey | |
| 54 | +benbro | |
| 55 | +Beni Cherniavsky-Paskin | |
| 56 | +Benjamin DeCoste | |
| 57 | +Ben Keen | |
| 58 | +Bernhard Sirlinger | |
| 59 | +Bert Chang | |
| 60 | +Billy Moon | |
| 61 | +binny | |
| 62 | +B Krishna Chaitanya | |
| 63 | +Blaine G | |
| 64 | +boomyjee | |
| 65 | +borawjm | |
| 66 | +Brandon Frohs | |
| 67 | +Brandon Wamboldt | |
| 68 | +Brett Zamir | |
| 69 | +Brian Grinstead | |
| 70 | +Brian Sletten | |
| 71 | +Bruce Mitchener | |
| 72 | +Chandra Sekhar Pydi | |
| 73 | +Charles Skelton | |
| 74 | +Cheah Chu Yeow | |
| 75 | +Chris Coyier | |
| 76 | +Chris Granger | |
| 77 | +Chris Houseknecht | |
| 78 | +Chris Morgan | |
| 79 | +Christopher Brown | |
| 80 | +ciaranj | |
| 81 | +CodeAnimal | |
| 82 | +ComFreek | |
| 83 | +Curtis Gagliardi | |
| 84 | +dagsta | |
| 85 | +daines | |
| 86 | +Dan Heberden | |
| 87 | +Daniel, Dao Quang Minh | |
| 88 | +Daniele Di Sarli | |
| 89 | +Daniel Faust | |
| 90 | +Daniel Huigens | |
| 91 | +Daniel KJ | |
| 92 | +Daniel Neel | |
| 93 | +Daniel Parnell | |
| 94 | +Danny Yoo | |
| 95 | +Darius Roberts | |
| 96 | +Dave Myers | |
| 97 | +David Mignot | |
| 98 | +David Pathakjee | |
| 99 | +deebugger | |
| 100 | +Deep Thought | |
| 101 | +dignifiedquire | |
| 102 | +domagoj412 | |
| 103 | +Dominator008 | |
| 104 | +Domizio Demichelis | |
| 105 | +Doug Wikle | |
| 106 | +Drew Bratcher | |
| 107 | +Drew Hintz | |
| 108 | +Drew Khoury | |
| 109 | +Dror BG | |
| 110 | +duralog | |
| 111 | +eborden | |
| 112 | +edsharp | |
| 113 | +ekhaled | |
| 114 | +Enam Mijbah Noor | |
| 115 | +Eric Allam | |
| 116 | +eustas | |
| 117 | +Fabien O'Carroll | |
| 118 | +Fabio Zendhi Nagao | |
| 119 | +Faiza Alsaied | |
| 120 | +Fauntleroy | |
| 121 | +fbuchinger | |
| 122 | +feizhang365 | |
| 123 | +Felipe Lalanne | |
| 124 | +Felix Raab | |
| 125 | +Filip Noetzel | |
| 126 | +flack | |
| 127 | +ForbesLindesay | |
| 128 | +Forbes Lindesay | |
| 129 | +Ford_Lawnmower | |
| 130 | +Frank Wiegand | |
| 131 | +Gabriel Horner | |
| 132 | +Gabriel Nahmias | |
| 133 | +galambalazs | |
| 134 | +Gautam Mehta | |
| 135 | +gekkoe | |
| 136 | +Gergely Hegykozi | |
| 137 | +Glenn Jorde | |
| 138 | +Glenn Ruehle | |
| 139 | +Golevka | |
| 140 | +Gordon Smith | |
| 141 | +Grant Skinner | |
| 142 | +greengiant | |
| 143 | +Guillaume Massé | |
| 144 | +Guillaume Massé | |
| 145 | +Gustavo Rodrigues | |
| 146 | +Hakan Tunc | |
| 147 | +Hans Engel | |
| 148 | +Hardest | |
| 149 | +Hasan Karahan | |
| 150 | +Hiroyuki Makino | |
| 151 | +hitsthings | |
| 152 | +Hocdoc | |
| 153 | +Ian Beck | |
| 154 | +Ian Dickinson | |
| 155 | +Ian Wehrman | |
| 156 | +Ian Wetherbee | |
| 157 | +Ice White | |
| 158 | +ICHIKAWA, Yuji | |
| 159 | +ilvalle | |
| 160 | +Ingo Richter | |
| 161 | +Irakli Gozalishvili | |
| 162 | +Ivan Kurnosov | |
| 163 | +Jacob Lee | |
| 164 | +Jakob Miland | |
| 165 | +Jakub Vrana | |
| 166 | +James Campos | |
| 167 | +James Thorne | |
| 168 | +Jamie Hill | |
| 169 | +Jan Jongboom | |
| 170 | +jankeromnes | |
| 171 | +Jan Keromnes | |
| 172 | +Jan Odvarko | |
| 173 | +Jan T. Sott | |
| 174 | +Jason | |
| 175 | +Jason Grout | |
| 176 | +Jason Johnston | |
| 177 | +Jason San Jose | |
| 178 | +Jason Siefken | |
| 179 | +Jaydeep Solanki | |
| 180 | +Jean Boussier | |
| 181 | +jeffkenton | |
| 182 | +Jeff Pickhardt | |
| 183 | +jem (graphite) | |
| 184 | +Jochen Berger | |
| 185 | +Johan Ask | |
| 186 | +John Connor | |
| 187 | +John Lees-Miller | |
| 188 | +John Snelson | |
| 189 | +John Van Der Loo | |
| 190 | +Jonathan Malmaud | |
| 191 | +jongalloway | |
| 192 | +Jon Malmaud | |
| 193 | +Joost-Wim Boekesteijn | |
| 194 | +Joseph Pecoraro | |
| 195 | +Joshua Newman | |
| 196 | +Josh Watzman | |
| 197 | +jots | |
| 198 | +jsoojeon | |
| 199 | +Juan Benavides Romero | |
| 200 | +Jucovschi Constantin | |
| 201 | +Juho Vuori | |
| 202 | +jwallers@gmail.com | |
| 203 | +kaniga | |
| 204 | +Ken Newman | |
| 205 | +Ken Rockot | |
| 206 | +Kevin Sawicki | |
| 207 | +Klaus Silveira | |
| 208 | +Koh Zi Han, Cliff | |
| 209 | +komakino | |
| 210 | +Konstantin Lopuhin | |
| 211 | +koops | |
| 212 | +ks-ifware | |
| 213 | +kubelsmieci | |
| 214 | +Lanny | |
| 215 | +Laszlo Vidacs | |
| 216 | +leaf corcoran | |
| 217 | +Leonid Khachaturov | |
| 218 | +Leonya Khachaturov | |
| 219 | +Liam Newman | |
| 220 | +LM | |
| 221 | +lochel | |
| 222 | +Lorenzo Stoakes | |
| 223 | +Luciano Longo | |
| 224 | +lynschinzer | |
| 225 | +Maksim Lin | |
| 226 | +Maksym Taran | |
| 227 | +Malay Majithia | |
| 228 | +Manuel Rego Casasnovas | |
| 229 | +Marat Dreizin | |
| 230 | +Marcel Gerber | |
| 231 | +Marco Aurélio | |
| 232 | +Marco Munizaga | |
| 233 | +Marcus Bointon | |
| 234 | +Marijn Haverbeke | |
| 235 | +Mario Pietsch | |
| 236 | +Mark Lentczner | |
| 237 | +Marko Bonaci | |
| 238 | +Martin Balek | |
| 239 | +Martín Gaitán | |
| 240 | +Martin Hasoň | |
| 241 | +Mason Malone | |
| 242 | +Mateusz Paprocki | |
| 243 | +Mathias Bynens | |
| 244 | +mats cronqvist | |
| 245 | +Matthew Beale | |
| 246 | +Matthias BUSSONNIER | |
| 247 | +Matt McDonald | |
| 248 | +Matt Pass | |
| 249 | +Matt Sacks | |
| 250 | +mauricio | |
| 251 | +Maximilian Hils | |
| 252 | +Maxim Kraev | |
| 253 | +Max Kirsch | |
| 254 | +mbarkhau | |
| 255 | +Metatheos | |
| 256 | +Micah Dubinko | |
| 257 | +Michael Lehenbauer | |
| 258 | +Michael Zhou | |
| 259 | +Mighty Guava | |
| 260 | +Miguel Castillo | |
| 261 | +Mike | |
| 262 | +Mike Brevoort | |
| 263 | +Mike Diaz | |
| 264 | +Mike Ivanov | |
| 265 | +Mike Kadin | |
| 266 | +MinRK | |
| 267 | +Miraculix87 | |
| 268 | +misfo | |
| 269 | +mloginov | |
| 270 | +mps | |
| 271 | +mtaran-google | |
| 272 | +Narciso Jaramillo | |
| 273 | +Nathan Williams | |
| 274 | +ndr | |
| 275 | +nerbert | |
| 276 | +nextrevision | |
| 277 | +nguillaumin | |
| 278 | +Ng Zhi An | |
| 279 | +Nicholas Bollweg | |
| 280 | +Nick Small | |
| 281 | +Niels van Groningen | |
| 282 | +Nikita Beloglazov | |
| 283 | +Nikita Vasilyev | |
| 284 | +Nikolay Kostov | |
| 285 | +nilp0inter | |
| 286 | +nlwillia | |
| 287 | +pablo | |
| 288 | +Page | |
| 289 | +Panupong Pasupat | |
| 290 | +paris | |
| 291 | +Patil Arpith | |
| 292 | +Patrick Strawderman | |
| 293 | +Paul Garvin | |
| 294 | +Paul Ivanov | |
| 295 | +Pavel Feldman | |
| 296 | +Pavel Strashkin | |
| 297 | +Paweł Bartkiewicz | |
| 298 | +peteguhl | |
| 299 | +Peter Flynn | |
| 300 | +peterkroon | |
| 301 | +Peter Kroon | |
| 302 | +prasanthj | |
| 303 | +Prasanth J | |
| 304 | +Radek Piórkowski | |
| 305 | +Rahul | |
| 306 | +Randy Edmunds | |
| 307 | +Rasmus Erik Voel Jensen | |
| 308 | +Richard van der Meer | |
| 309 | +Richard Z.H. Wang | |
| 310 | +Roberto Abdelkader Martínez Pérez | |
| 311 | +robertop23 | |
| 312 | +Robert Plummer | |
| 313 | +Ruslan Osmanov | |
| 314 | +Ryan Prior | |
| 315 | +sabaca | |
| 316 | +Samuel Ainsworth | |
| 317 | +sandeepshetty | |
| 318 | +Sander AKA Redsandro | |
| 319 | +santec | |
| 320 | +Sascha Peilicke | |
| 321 | +satchmorun | |
| 322 | +sathyamoorthi | |
| 323 | +SCLINIC\jdecker | |
| 324 | +Scott Aikin | |
| 325 | +Sebastian Zaha | |
| 326 | +shaund | |
| 327 | +shaun gilchrist | |
| 328 | +Shawn A | |
| 329 | +sheopory | |
| 330 | +Shiv Deepak | |
| 331 | +Shmuel Englard | |
| 332 | +Shubham Jain | |
| 333 | +snasa | |
| 334 | +soliton4 | |
| 335 | +sonson | |
| 336 | +spastorelli | |
| 337 | +srajanpaliwal | |
| 338 | +Stanislav Oaserele | |
| 339 | +Stas Kobzar | |
| 340 | +Stefan Borsje | |
| 341 | +Steffen Beyer | |
| 342 | +Steve O'Hara | |
| 343 | +stoskov | |
| 344 | +Taha Jahangir | |
| 345 | +Takuji Shimokawa | |
| 346 | +Tarmil | |
| 347 | +tfjgeorge | |
| 348 | +Thaddee Tyl | |
| 349 | +TheHowl | |
| 350 | +think | |
| 351 | +Thomas Dvornik | |
| 352 | +Thomas Schmid | |
| 353 | +Tim Alby | |
| 354 | +Tim Baumann | |
| 355 | +Timothy Farrell | |
| 356 | +Timothy Hatcher | |
| 357 | +TobiasBg | |
| 358 | +Tomas-A | |
| 359 | +Tomas Varaneckas | |
| 360 | +Tom Erik Støwer | |
| 361 | +Tom MacWright | |
| 362 | +Tony Jian | |
| 363 | +Travis Heppe | |
| 364 | +Triangle717 | |
| 365 | +twifkak | |
| 366 | +Vestimir Markov | |
| 367 | +vf | |
| 368 | +Vincent Woo | |
| 369 | +Volker Mische | |
| 370 | +wenli | |
| 371 | +Wesley Wiser | |
| 372 | +William Jamieson | |
| 373 | +William Stein | |
| 374 | +Wojtek Ptak | |
| 375 | +Xavier Mendez | |
| 376 | +YNH Webdev | |
| 377 | +Yunchi Luo | |
| 378 | +Yuvi Panda | |
| 379 | +Zachary Dremann | |
| 380 | +zziuni | |
| 381 | +魏鹏刚 | ... | ... |
| ... | ... | @@ -0,0 +1,76 @@ |
| 1 | +# How to contribute | |
| 2 | + | |
| 3 | +- [Getting help](#getting-help-) | |
| 4 | +- [Submitting bug reports](#submitting-bug-reports-) | |
| 5 | +- [Contributing code](#contributing-code-) | |
| 6 | + | |
| 7 | +## Getting help | |
| 8 | + | |
| 9 | +Community discussion, questions, and informal bug reporting is done on the | |
| 10 | +[CodeMirror Google group](http://groups.google.com/group/codemirror). | |
| 11 | + | |
| 12 | +## Submitting bug reports | |
| 13 | + | |
| 14 | +The preferred way to report bugs is to use the | |
| 15 | +[GitHub issue tracker](http://github.com/marijnh/CodeMirror/issues). Before | |
| 16 | +reporting a bug, read these pointers. | |
| 17 | + | |
| 18 | +**Note:** The issue tracker is for *bugs*, not requests for help. Questions | |
| 19 | +should be asked on the | |
| 20 | +[CodeMirror Google group](http://groups.google.com/group/codemirror) instead. | |
| 21 | + | |
| 22 | +### Reporting bugs effectively | |
| 23 | + | |
| 24 | +- CodeMirror is maintained by volunteers. They don't owe you anything, so be | |
| 25 | + polite. Reports with an indignant or belligerent tone tend to be moved to the | |
| 26 | + bottom of the pile. | |
| 27 | + | |
| 28 | +- Include information about **the browser in which the problem occurred**. Even | |
| 29 | + if you tested several browsers, and the problem occurred in all of them, | |
| 30 | + mention this fact in the bug report. Also include browser version numbers and | |
| 31 | + the operating system that you're on. | |
| 32 | + | |
| 33 | +- Mention which release of CodeMirror you're using. Preferably, try also with | |
| 34 | + the current development snapshot, to ensure the problem has not already been | |
| 35 | + fixed. | |
| 36 | + | |
| 37 | +- Mention very precisely what went wrong. "X is broken" is not a good bug | |
| 38 | + report. What did you expect to happen? What happened instead? Describe the | |
| 39 | + exact steps a maintainer has to take to make the problem occur. We can not | |
| 40 | + fix something that we can not observe. | |
| 41 | + | |
| 42 | +- If the problem can not be reproduced in any of the demos included in the | |
| 43 | + CodeMirror distribution, please provide an HTML document that demonstrates | |
| 44 | + the problem. The best way to do this is to go to | |
| 45 | + [jsbin.com](http://jsbin.com/ihunin/edit), enter it there, press save, and | |
| 46 | + include the resulting link in your bug report. | |
| 47 | + | |
| 48 | +## Contributing code | |
| 49 | + | |
| 50 | +- Make sure you have a [GitHub Account](https://github.com/signup/free) | |
| 51 | +- Fork [CodeMirror](https://github.com/marijnh/CodeMirror/) | |
| 52 | + ([how to fork a repo](https://help.github.com/articles/fork-a-repo)) | |
| 53 | +- Make your changes | |
| 54 | +- If your changes are easy to test or likely to regress, add tests. | |
| 55 | + Tests for the core go into `test/test.js`, some modes have their own | |
| 56 | + test suite under `mode/XXX/test.js`. Feel free to add new test | |
| 57 | + suites to modes that don't have one yet (be sure to link the new | |
| 58 | + tests into `test/index.html`). | |
| 59 | +- Follow the general code style of the rest of the project (see | |
| 60 | + below). Run `bin/lint` to verify that the linter is happy. | |
| 61 | +- Make sure all tests pass. Visit `test/index.html` in your browser to | |
| 62 | + run them. | |
| 63 | +- Submit a pull request | |
| 64 | +([how to create a pull request](https://help.github.com/articles/fork-a-repo)) | |
| 65 | + | |
| 66 | +### Coding standards | |
| 67 | + | |
| 68 | +- 2 spaces per indentation level, no tabs. | |
| 69 | +- Include semicolons after statements. | |
| 70 | +- Note that the linter (`bin/lint`) which is run after each commit | |
| 71 | + complains about unused variables and functions. Prefix their names | |
| 72 | + with an underscore to muffle it. | |
| 73 | + | |
| 74 | +- CodeMirror does *not* follow JSHint or JSLint prescribed style. | |
| 75 | + Patches that try to 'fix' code to pass one of these linters will be | |
| 76 | + unceremoniously discarded. | ... | ... |
| ... | ... | @@ -0,0 +1,19 @@ |
| 1 | +Copyright (C) 2014 by Marijn Haverbeke <marijnh@gmail.com> and others | |
| 2 | + | |
| 3 | +Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 4 | +of this software and associated documentation files (the "Software"), to deal | |
| 5 | +in the Software without restriction, including without limitation the rights | |
| 6 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 7 | +copies of the Software, and to permit persons to whom the Software is | |
| 8 | +furnished to do so, subject to the following conditions: | |
| 9 | + | |
| 10 | +The above copyright notice and this permission notice shall be included in | |
| 11 | +all copies or substantial portions of the Software. | |
| 12 | + | |
| 13 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 14 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 15 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 16 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 17 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 18 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 19 | +THE SOFTWARE. | ... | ... |
| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | +# CodeMirror | |
| 2 | +[](https://travis-ci.org/marijnh/CodeMirror) | |
| 3 | +[](https://www.npmjs.org/package/codemirror) | |
| 4 | + | |
| 5 | +CodeMirror is a JavaScript component that provides a code editor in | |
| 6 | +the browser. When a mode is available for the language you are coding | |
| 7 | +in, it will color your code, and optionally help with indentation. | |
| 8 | + | |
| 9 | +The project page is http://codemirror.net | |
| 10 | +The manual is at http://codemirror.net/doc/manual.html | |
| 11 | +The contributing guidelines are in [CONTRIBUTING.md](https://github.com/marijnh/CodeMirror/blob/master/CONTRIBUTING.md) | ... | ... |
| ... | ... | @@ -0,0 +1,183 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + "use strict"; | |
| 13 | + | |
| 14 | + var noOptions = {}; | |
| 15 | + var nonWS = /[^\s\u00a0]/; | |
| 16 | + var Pos = CodeMirror.Pos; | |
| 17 | + | |
| 18 | + function firstNonWS(str) { | |
| 19 | + var found = str.search(nonWS); | |
| 20 | + return found == -1 ? 0 : found; | |
| 21 | + } | |
| 22 | + | |
| 23 | + CodeMirror.commands.toggleComment = function(cm) { | |
| 24 | + var minLine = Infinity, ranges = cm.listSelections(), mode = null; | |
| 25 | + for (var i = ranges.length - 1; i >= 0; i--) { | |
| 26 | + var from = ranges[i].from(), to = ranges[i].to(); | |
| 27 | + if (from.line >= minLine) continue; | |
| 28 | + if (to.line >= minLine) to = Pos(minLine, 0); | |
| 29 | + minLine = from.line; | |
| 30 | + if (mode == null) { | |
| 31 | + if (cm.uncomment(from, to)) mode = "un"; | |
| 32 | + else { cm.lineComment(from, to); mode = "line"; } | |
| 33 | + } else if (mode == "un") { | |
| 34 | + cm.uncomment(from, to); | |
| 35 | + } else { | |
| 36 | + cm.lineComment(from, to); | |
| 37 | + } | |
| 38 | + } | |
| 39 | + }; | |
| 40 | + | |
| 41 | + CodeMirror.defineExtension("lineComment", function(from, to, options) { | |
| 42 | + if (!options) options = noOptions; | |
| 43 | + var self = this, mode = self.getModeAt(from); | |
| 44 | + var commentString = options.lineComment || mode.lineComment; | |
| 45 | + if (!commentString) { | |
| 46 | + if (options.blockCommentStart || mode.blockCommentStart) { | |
| 47 | + options.fullLines = true; | |
| 48 | + self.blockComment(from, to, options); | |
| 49 | + } | |
| 50 | + return; | |
| 51 | + } | |
| 52 | + var firstLine = self.getLine(from.line); | |
| 53 | + if (firstLine == null) return; | |
| 54 | + var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1); | |
| 55 | + var pad = options.padding == null ? " " : options.padding; | |
| 56 | + var blankLines = options.commentBlankLines || from.line == to.line; | |
| 57 | + | |
| 58 | + self.operation(function() { | |
| 59 | + if (options.indent) { | |
| 60 | + var baseString = firstLine.slice(0, firstNonWS(firstLine)); | |
| 61 | + for (var i = from.line; i < end; ++i) { | |
| 62 | + var line = self.getLine(i), cut = baseString.length; | |
| 63 | + if (!blankLines && !nonWS.test(line)) continue; | |
| 64 | + if (line.slice(0, cut) != baseString) cut = firstNonWS(line); | |
| 65 | + self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut)); | |
| 66 | + } | |
| 67 | + } else { | |
| 68 | + for (var i = from.line; i < end; ++i) { | |
| 69 | + if (blankLines || nonWS.test(self.getLine(i))) | |
| 70 | + self.replaceRange(commentString + pad, Pos(i, 0)); | |
| 71 | + } | |
| 72 | + } | |
| 73 | + }); | |
| 74 | + }); | |
| 75 | + | |
| 76 | + CodeMirror.defineExtension("blockComment", function(from, to, options) { | |
| 77 | + if (!options) options = noOptions; | |
| 78 | + var self = this, mode = self.getModeAt(from); | |
| 79 | + var startString = options.blockCommentStart || mode.blockCommentStart; | |
| 80 | + var endString = options.blockCommentEnd || mode.blockCommentEnd; | |
| 81 | + if (!startString || !endString) { | |
| 82 | + if ((options.lineComment || mode.lineComment) && options.fullLines != false) | |
| 83 | + self.lineComment(from, to, options); | |
| 84 | + return; | |
| 85 | + } | |
| 86 | + | |
| 87 | + var end = Math.min(to.line, self.lastLine()); | |
| 88 | + if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end; | |
| 89 | + | |
| 90 | + var pad = options.padding == null ? " " : options.padding; | |
| 91 | + if (from.line > end) return; | |
| 92 | + | |
| 93 | + self.operation(function() { | |
| 94 | + if (options.fullLines != false) { | |
| 95 | + var lastLineHasText = nonWS.test(self.getLine(end)); | |
| 96 | + self.replaceRange(pad + endString, Pos(end)); | |
| 97 | + self.replaceRange(startString + pad, Pos(from.line, 0)); | |
| 98 | + var lead = options.blockCommentLead || mode.blockCommentLead; | |
| 99 | + if (lead != null) for (var i = from.line + 1; i <= end; ++i) | |
| 100 | + if (i != end || lastLineHasText) | |
| 101 | + self.replaceRange(lead + pad, Pos(i, 0)); | |
| 102 | + } else { | |
| 103 | + self.replaceRange(endString, to); | |
| 104 | + self.replaceRange(startString, from); | |
| 105 | + } | |
| 106 | + }); | |
| 107 | + }); | |
| 108 | + | |
| 109 | + CodeMirror.defineExtension("uncomment", function(from, to, options) { | |
| 110 | + if (!options) options = noOptions; | |
| 111 | + var self = this, mode = self.getModeAt(from); | |
| 112 | + var end = Math.min(to.line, self.lastLine()), start = Math.min(from.line, end); | |
| 113 | + | |
| 114 | + // Try finding line comments | |
| 115 | + var lineString = options.lineComment || mode.lineComment, lines = []; | |
| 116 | + var pad = options.padding == null ? " " : options.padding, didSomething; | |
| 117 | + lineComment: { | |
| 118 | + if (!lineString) break lineComment; | |
| 119 | + for (var i = start; i <= end; ++i) { | |
| 120 | + var line = self.getLine(i); | |
| 121 | + var found = line.indexOf(lineString); | |
| 122 | + if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1; | |
| 123 | + if (found == -1 && (i != end || i == start) && nonWS.test(line)) break lineComment; | |
| 124 | + if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment; | |
| 125 | + lines.push(line); | |
| 126 | + } | |
| 127 | + self.operation(function() { | |
| 128 | + for (var i = start; i <= end; ++i) { | |
| 129 | + var line = lines[i - start]; | |
| 130 | + var pos = line.indexOf(lineString), endPos = pos + lineString.length; | |
| 131 | + if (pos < 0) continue; | |
| 132 | + if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length; | |
| 133 | + didSomething = true; | |
| 134 | + self.replaceRange("", Pos(i, pos), Pos(i, endPos)); | |
| 135 | + } | |
| 136 | + }); | |
| 137 | + if (didSomething) return true; | |
| 138 | + } | |
| 139 | + | |
| 140 | + // Try block comments | |
| 141 | + var startString = options.blockCommentStart || mode.blockCommentStart; | |
| 142 | + var endString = options.blockCommentEnd || mode.blockCommentEnd; | |
| 143 | + if (!startString || !endString) return false; | |
| 144 | + var lead = options.blockCommentLead || mode.blockCommentLead; | |
| 145 | + var startLine = self.getLine(start), endLine = end == start ? startLine : self.getLine(end); | |
| 146 | + var open = startLine.indexOf(startString), close = endLine.lastIndexOf(endString); | |
| 147 | + if (close == -1 && start != end) { | |
| 148 | + endLine = self.getLine(--end); | |
| 149 | + close = endLine.lastIndexOf(endString); | |
| 150 | + } | |
| 151 | + if (open == -1 || close == -1 || | |
| 152 | + !/comment/.test(self.getTokenTypeAt(Pos(start, open + 1))) || | |
| 153 | + !/comment/.test(self.getTokenTypeAt(Pos(end, close + 1)))) | |
| 154 | + return false; | |
| 155 | + | |
| 156 | + // Avoid killing block comments completely outside the selection. | |
| 157 | + // Positions of the last startString before the start of the selection, and the first endString after it. | |
| 158 | + var lastStart = startLine.lastIndexOf(startString, from.ch); | |
| 159 | + var firstEnd = lastStart == -1 ? -1 : startLine.slice(0, from.ch).indexOf(endString, lastStart + startString.length); | |
| 160 | + if (lastStart != -1 && firstEnd != -1 && firstEnd + endString.length != from.ch) return false; | |
| 161 | + // Positions of the first endString after the end of the selection, and the last startString before it. | |
| 162 | + firstEnd = endLine.indexOf(endString, to.ch); | |
| 163 | + var almostLastStart = endLine.slice(to.ch).lastIndexOf(startString, firstEnd - to.ch); | |
| 164 | + lastStart = (firstEnd == -1 || almostLastStart == -1) ? -1 : to.ch + almostLastStart; | |
| 165 | + if (firstEnd != -1 && lastStart != -1 && lastStart != to.ch) return false; | |
| 166 | + | |
| 167 | + self.operation(function() { | |
| 168 | + self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)), | |
| 169 | + Pos(end, close + endString.length)); | |
| 170 | + var openEnd = open + startString.length; | |
| 171 | + if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length; | |
| 172 | + self.replaceRange("", Pos(start, open), Pos(start, openEnd)); | |
| 173 | + if (lead) for (var i = start + 1; i <= end; ++i) { | |
| 174 | + var line = self.getLine(i), found = line.indexOf(lead); | |
| 175 | + if (found == -1 || nonWS.test(line.slice(0, found))) continue; | |
| 176 | + var foundEnd = found + lead.length; | |
| 177 | + if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length; | |
| 178 | + self.replaceRange("", Pos(i, found), Pos(i, foundEnd)); | |
| 179 | + } | |
| 180 | + }); | |
| 181 | + return true; | |
| 182 | + }); | |
| 183 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,85 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + var modes = ["clike", "css", "javascript"]; | |
| 13 | + | |
| 14 | + for (var i = 0; i < modes.length; ++i) | |
| 15 | + CodeMirror.extendMode(modes[i], {blockCommentContinue: " * "}); | |
| 16 | + | |
| 17 | + function continueComment(cm) { | |
| 18 | + if (cm.getOption("disableInput")) return CodeMirror.Pass; | |
| 19 | + var ranges = cm.listSelections(), mode, inserts = []; | |
| 20 | + for (var i = 0; i < ranges.length; i++) { | |
| 21 | + var pos = ranges[i].head, token = cm.getTokenAt(pos); | |
| 22 | + if (token.type != "comment") return CodeMirror.Pass; | |
| 23 | + var modeHere = CodeMirror.innerMode(cm.getMode(), token.state).mode; | |
| 24 | + if (!mode) mode = modeHere; | |
| 25 | + else if (mode != modeHere) return CodeMirror.Pass; | |
| 26 | + | |
| 27 | + var insert = null; | |
| 28 | + if (mode.blockCommentStart && mode.blockCommentContinue) { | |
| 29 | + var end = token.string.indexOf(mode.blockCommentEnd); | |
| 30 | + var full = cm.getRange(CodeMirror.Pos(pos.line, 0), CodeMirror.Pos(pos.line, token.end)), found; | |
| 31 | + if (end != -1 && end == token.string.length - mode.blockCommentEnd.length && pos.ch >= end) { | |
| 32 | + // Comment ended, don't continue it | |
| 33 | + } else if (token.string.indexOf(mode.blockCommentStart) == 0) { | |
| 34 | + insert = full.slice(0, token.start); | |
| 35 | + if (!/^\s*$/.test(insert)) { | |
| 36 | + insert = ""; | |
| 37 | + for (var j = 0; j < token.start; ++j) insert += " "; | |
| 38 | + } | |
| 39 | + } else if ((found = full.indexOf(mode.blockCommentContinue)) != -1 && | |
| 40 | + found + mode.blockCommentContinue.length > token.start && | |
| 41 | + /^\s*$/.test(full.slice(0, found))) { | |
| 42 | + insert = full.slice(0, found); | |
| 43 | + } | |
| 44 | + if (insert != null) insert += mode.blockCommentContinue; | |
| 45 | + } | |
| 46 | + if (insert == null && mode.lineComment && continueLineCommentEnabled(cm)) { | |
| 47 | + var line = cm.getLine(pos.line), found = line.indexOf(mode.lineComment); | |
| 48 | + if (found > -1) { | |
| 49 | + insert = line.slice(0, found); | |
| 50 | + if (/\S/.test(insert)) insert = null; | |
| 51 | + else insert += mode.lineComment + line.slice(found + mode.lineComment.length).match(/^\s*/)[0]; | |
| 52 | + } | |
| 53 | + } | |
| 54 | + if (insert == null) return CodeMirror.Pass; | |
| 55 | + inserts[i] = "\n" + insert; | |
| 56 | + } | |
| 57 | + | |
| 58 | + cm.operation(function() { | |
| 59 | + for (var i = ranges.length - 1; i >= 0; i--) | |
| 60 | + cm.replaceRange(inserts[i], ranges[i].from(), ranges[i].to(), "+insert"); | |
| 61 | + }); | |
| 62 | + } | |
| 63 | + | |
| 64 | + function continueLineCommentEnabled(cm) { | |
| 65 | + var opt = cm.getOption("continueComments"); | |
| 66 | + if (opt && typeof opt == "object") | |
| 67 | + return opt.continueLineComment !== false; | |
| 68 | + return true; | |
| 69 | + } | |
| 70 | + | |
| 71 | + CodeMirror.defineOption("continueComments", null, function(cm, val, prev) { | |
| 72 | + if (prev && prev != CodeMirror.Init) | |
| 73 | + cm.removeKeyMap("continueComment"); | |
| 74 | + if (val) { | |
| 75 | + var key = "Enter"; | |
| 76 | + if (typeof val == "string") | |
| 77 | + key = val; | |
| 78 | + else if (typeof val == "object" && val.key) | |
| 79 | + key = val.key; | |
| 80 | + var map = {name: "continueComment"}; | |
| 81 | + map[key] = continueComment; | |
| 82 | + cm.addKeyMap(map); | |
| 83 | + } | |
| 84 | + }); | |
| 85 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,32 @@ |
| 1 | +.CodeMirror-dialog { | |
| 2 | + position: absolute; | |
| 3 | + left: 0; right: 0; | |
| 4 | + background: white; | |
| 5 | + z-index: 15; | |
| 6 | + padding: .1em .8em; | |
| 7 | + overflow: hidden; | |
| 8 | + color: #333; | |
| 9 | +} | |
| 10 | + | |
| 11 | +.CodeMirror-dialog-top { | |
| 12 | + border-bottom: 1px solid #eee; | |
| 13 | + top: 0; | |
| 14 | +} | |
| 15 | + | |
| 16 | +.CodeMirror-dialog-bottom { | |
| 17 | + border-top: 1px solid #eee; | |
| 18 | + bottom: 0; | |
| 19 | +} | |
| 20 | + | |
| 21 | +.CodeMirror-dialog input { | |
| 22 | + border: none; | |
| 23 | + outline: none; | |
| 24 | + background: transparent; | |
| 25 | + width: 20em; | |
| 26 | + color: inherit; | |
| 27 | + font-family: monospace; | |
| 28 | +} | |
| 29 | + | |
| 30 | +.CodeMirror-dialog button { | |
| 31 | + font-size: 70%; | |
| 32 | +} | ... | ... |
| ... | ... | @@ -0,0 +1,152 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +// Open simple dialogs on top of an editor. Relies on dialog.css. | |
| 5 | + | |
| 6 | +(function(mod) { | |
| 7 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 8 | + mod(require("../../lib/codemirror")); | |
| 9 | + else if (typeof define == "function" && define.amd) // AMD | |
| 10 | + define(["../../lib/codemirror"], mod); | |
| 11 | + else // Plain browser env | |
| 12 | + mod(CodeMirror); | |
| 13 | +})(function(CodeMirror) { | |
| 14 | + function dialogDiv(cm, template, bottom) { | |
| 15 | + var wrap = cm.getWrapperElement(); | |
| 16 | + var dialog; | |
| 17 | + dialog = wrap.appendChild(document.createElement("div")); | |
| 18 | + if (bottom) | |
| 19 | + dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom"; | |
| 20 | + else | |
| 21 | + dialog.className = "CodeMirror-dialog CodeMirror-dialog-top"; | |
| 22 | + | |
| 23 | + if (typeof template == "string") { | |
| 24 | + dialog.innerHTML = template; | |
| 25 | + } else { // Assuming it's a detached DOM element. | |
| 26 | + dialog.appendChild(template); | |
| 27 | + } | |
| 28 | + return dialog; | |
| 29 | + } | |
| 30 | + | |
| 31 | + function closeNotification(cm, newVal) { | |
| 32 | + if (cm.state.currentNotificationClose) | |
| 33 | + cm.state.currentNotificationClose(); | |
| 34 | + cm.state.currentNotificationClose = newVal; | |
| 35 | + } | |
| 36 | + | |
| 37 | + CodeMirror.defineExtension("openDialog", function(template, callback, options) { | |
| 38 | + if (!options) options = {}; | |
| 39 | + | |
| 40 | + closeNotification(this, null); | |
| 41 | + | |
| 42 | + var dialog = dialogDiv(this, template, options.bottom); | |
| 43 | + var closed = false, me = this; | |
| 44 | + function close(newVal) { | |
| 45 | + if (typeof newVal == 'string') { | |
| 46 | + inp.value = newVal; | |
| 47 | + } else { | |
| 48 | + if (closed) return; | |
| 49 | + closed = true; | |
| 50 | + dialog.parentNode.removeChild(dialog); | |
| 51 | + me.focus(); | |
| 52 | + | |
| 53 | + if (options.onClose) options.onClose(dialog); | |
| 54 | + } | |
| 55 | + } | |
| 56 | + | |
| 57 | + var inp = dialog.getElementsByTagName("input")[0], button; | |
| 58 | + if (inp) { | |
| 59 | + if (options.value) inp.value = options.value; | |
| 60 | + | |
| 61 | + if (options.onInput) | |
| 62 | + CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);}); | |
| 63 | + if (options.onKeyUp) | |
| 64 | + CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);}); | |
| 65 | + | |
| 66 | + CodeMirror.on(inp, "keydown", function(e) { | |
| 67 | + if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; } | |
| 68 | + if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) { | |
| 69 | + inp.blur(); | |
| 70 | + CodeMirror.e_stop(e); | |
| 71 | + close(); | |
| 72 | + } | |
| 73 | + if (e.keyCode == 13) callback(inp.value); | |
| 74 | + }); | |
| 75 | + | |
| 76 | + if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close); | |
| 77 | + | |
| 78 | + inp.focus(); | |
| 79 | + } else if (button = dialog.getElementsByTagName("button")[0]) { | |
| 80 | + CodeMirror.on(button, "click", function() { | |
| 81 | + close(); | |
| 82 | + me.focus(); | |
| 83 | + }); | |
| 84 | + | |
| 85 | + if (options.closeOnBlur !== false) CodeMirror.on(button, "blur", close); | |
| 86 | + | |
| 87 | + button.focus(); | |
| 88 | + } | |
| 89 | + return close; | |
| 90 | + }); | |
| 91 | + | |
| 92 | + CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) { | |
| 93 | + closeNotification(this, null); | |
| 94 | + var dialog = dialogDiv(this, template, options && options.bottom); | |
| 95 | + var buttons = dialog.getElementsByTagName("button"); | |
| 96 | + var closed = false, me = this, blurring = 1; | |
| 97 | + function close() { | |
| 98 | + if (closed) return; | |
| 99 | + closed = true; | |
| 100 | + dialog.parentNode.removeChild(dialog); | |
| 101 | + me.focus(); | |
| 102 | + } | |
| 103 | + buttons[0].focus(); | |
| 104 | + for (var i = 0; i < buttons.length; ++i) { | |
| 105 | + var b = buttons[i]; | |
| 106 | + (function(callback) { | |
| 107 | + CodeMirror.on(b, "click", function(e) { | |
| 108 | + CodeMirror.e_preventDefault(e); | |
| 109 | + close(); | |
| 110 | + if (callback) callback(me); | |
| 111 | + }); | |
| 112 | + })(callbacks[i]); | |
| 113 | + CodeMirror.on(b, "blur", function() { | |
| 114 | + --blurring; | |
| 115 | + setTimeout(function() { if (blurring <= 0) close(); }, 200); | |
| 116 | + }); | |
| 117 | + CodeMirror.on(b, "focus", function() { ++blurring; }); | |
| 118 | + } | |
| 119 | + }); | |
| 120 | + | |
| 121 | + /* | |
| 122 | + * openNotification | |
| 123 | + * Opens a notification, that can be closed with an optional timer | |
| 124 | + * (default 5000ms timer) and always closes on click. | |
| 125 | + * | |
| 126 | + * If a notification is opened while another is opened, it will close the | |
| 127 | + * currently opened one and open the new one immediately. | |
| 128 | + */ | |
| 129 | + CodeMirror.defineExtension("openNotification", function(template, options) { | |
| 130 | + closeNotification(this, close); | |
| 131 | + var dialog = dialogDiv(this, template, options && options.bottom); | |
| 132 | + var closed = false, doneTimer; | |
| 133 | + var duration = options && typeof options.duration !== "undefined" ? options.duration : 5000; | |
| 134 | + | |
| 135 | + function close() { | |
| 136 | + if (closed) return; | |
| 137 | + closed = true; | |
| 138 | + clearTimeout(doneTimer); | |
| 139 | + dialog.parentNode.removeChild(dialog); | |
| 140 | + } | |
| 141 | + | |
| 142 | + CodeMirror.on(dialog, 'click', function(e) { | |
| 143 | + CodeMirror.e_preventDefault(e); | |
| 144 | + close(); | |
| 145 | + }); | |
| 146 | + | |
| 147 | + if (duration) | |
| 148 | + doneTimer = setTimeout(close, duration); | |
| 149 | + | |
| 150 | + return close; | |
| 151 | + }); | |
| 152 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,41 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + "use strict"; | |
| 13 | + | |
| 14 | + CodeMirror.defineOption("fullScreen", false, function(cm, val, old) { | |
| 15 | + if (old == CodeMirror.Init) old = false; | |
| 16 | + if (!old == !val) return; | |
| 17 | + if (val) setFullscreen(cm); | |
| 18 | + else setNormal(cm); | |
| 19 | + }); | |
| 20 | + | |
| 21 | + function setFullscreen(cm) { | |
| 22 | + var wrap = cm.getWrapperElement(); | |
| 23 | + cm.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset, | |
| 24 | + width: wrap.style.width, height: wrap.style.height}; | |
| 25 | + wrap.style.width = ""; | |
| 26 | + wrap.style.height = "auto"; | |
| 27 | + wrap.className += " CodeMirror-fullscreen"; | |
| 28 | + document.documentElement.style.overflow = "hidden"; | |
| 29 | + cm.refresh(); | |
| 30 | + } | |
| 31 | + | |
| 32 | + function setNormal(cm) { | |
| 33 | + var wrap = cm.getWrapperElement(); | |
| 34 | + wrap.className = wrap.className.replace(/\s*CodeMirror-fullscreen\b/, ""); | |
| 35 | + document.documentElement.style.overflow = ""; | |
| 36 | + var info = cm.state.fullScreenRestore; | |
| 37 | + wrap.style.width = info.width; wrap.style.height = info.height; | |
| 38 | + window.scrollTo(info.scrollLeft, info.scrollTop); | |
| 39 | + cm.refresh(); | |
| 40 | + } | |
| 41 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,58 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + CodeMirror.defineOption("placeholder", "", function(cm, val, old) { | |
| 13 | + var prev = old && old != CodeMirror.Init; | |
| 14 | + if (val && !prev) { | |
| 15 | + cm.on("blur", onBlur); | |
| 16 | + cm.on("change", onChange); | |
| 17 | + onChange(cm); | |
| 18 | + } else if (!val && prev) { | |
| 19 | + cm.off("blur", onBlur); | |
| 20 | + cm.off("change", onChange); | |
| 21 | + clearPlaceholder(cm); | |
| 22 | + var wrapper = cm.getWrapperElement(); | |
| 23 | + wrapper.className = wrapper.className.replace(" CodeMirror-empty", ""); | |
| 24 | + } | |
| 25 | + | |
| 26 | + if (val && !cm.hasFocus()) onBlur(cm); | |
| 27 | + }); | |
| 28 | + | |
| 29 | + function clearPlaceholder(cm) { | |
| 30 | + if (cm.state.placeholder) { | |
| 31 | + cm.state.placeholder.parentNode.removeChild(cm.state.placeholder); | |
| 32 | + cm.state.placeholder = null; | |
| 33 | + } | |
| 34 | + } | |
| 35 | + function setPlaceholder(cm) { | |
| 36 | + clearPlaceholder(cm); | |
| 37 | + var elt = cm.state.placeholder = document.createElement("pre"); | |
| 38 | + elt.style.cssText = "height: 0; overflow: visible"; | |
| 39 | + elt.className = "CodeMirror-placeholder"; | |
| 40 | + elt.appendChild(document.createTextNode(cm.getOption("placeholder"))); | |
| 41 | + cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild); | |
| 42 | + } | |
| 43 | + | |
| 44 | + function onBlur(cm) { | |
| 45 | + if (isEmpty(cm)) setPlaceholder(cm); | |
| 46 | + } | |
| 47 | + function onChange(cm) { | |
| 48 | + var wrapper = cm.getWrapperElement(), empty = isEmpty(cm); | |
| 49 | + wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : ""); | |
| 50 | + | |
| 51 | + if (empty) setPlaceholder(cm); | |
| 52 | + else clearPlaceholder(cm); | |
| 53 | + } | |
| 54 | + | |
| 55 | + function isEmpty(cm) { | |
| 56 | + return (cm.lineCount() === 1) && (cm.getLine(0) === ""); | |
| 57 | + } | |
| 58 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,64 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + "use strict"; | |
| 13 | + | |
| 14 | + CodeMirror.defineOption("rulers", false, function(cm, val, old) { | |
| 15 | + if (old && old != CodeMirror.Init) { | |
| 16 | + clearRulers(cm); | |
| 17 | + cm.off("refresh", refreshRulers); | |
| 18 | + } | |
| 19 | + if (val && val.length) { | |
| 20 | + setRulers(cm); | |
| 21 | + cm.on("refresh", refreshRulers); | |
| 22 | + } | |
| 23 | + }); | |
| 24 | + | |
| 25 | + function clearRulers(cm) { | |
| 26 | + for (var i = cm.display.lineSpace.childNodes.length - 1; i >= 0; i--) { | |
| 27 | + var node = cm.display.lineSpace.childNodes[i]; | |
| 28 | + if (/(^|\s)CodeMirror-ruler($|\s)/.test(node.className)) | |
| 29 | + node.parentNode.removeChild(node); | |
| 30 | + } | |
| 31 | + } | |
| 32 | + | |
| 33 | + function setRulers(cm) { | |
| 34 | + var val = cm.getOption("rulers"); | |
| 35 | + var cw = cm.defaultCharWidth(); | |
| 36 | + var left = cm.charCoords(CodeMirror.Pos(cm.firstLine(), 0), "div").left; | |
| 37 | + var minH = cm.display.scroller.offsetHeight + 30; | |
| 38 | + for (var i = 0; i < val.length; i++) { | |
| 39 | + var elt = document.createElement("div"); | |
| 40 | + elt.className = "CodeMirror-ruler"; | |
| 41 | + var col, cls = null, conf = val[i]; | |
| 42 | + if (typeof conf == "number") { | |
| 43 | + col = conf; | |
| 44 | + } else { | |
| 45 | + col = conf.column; | |
| 46 | + if (conf.className) elt.className += " " + conf.className; | |
| 47 | + if (conf.color) elt.style.borderColor = conf.color; | |
| 48 | + if (conf.lineStyle) elt.style.borderLeftStyle = conf.lineStyle; | |
| 49 | + if (conf.width) elt.style.borderLeftWidth = conf.width; | |
| 50 | + cls = val[i].className; | |
| 51 | + } | |
| 52 | + elt.style.left = (left + col * cw) + "px"; | |
| 53 | + elt.style.top = "-50px"; | |
| 54 | + elt.style.bottom = "-20px"; | |
| 55 | + elt.style.minHeight = minH + "px"; | |
| 56 | + cm.display.lineSpace.insertBefore(elt, cm.display.cursorDiv); | |
| 57 | + } | |
| 58 | + } | |
| 59 | + | |
| 60 | + function refreshRulers(cm) { | |
| 61 | + clearRulers(cm); | |
| 62 | + setRulers(cm); | |
| 63 | + } | |
| 64 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,158 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + var DEFAULT_BRACKETS = "()[]{}''\"\""; | |
| 13 | + var DEFAULT_EXPLODE_ON_ENTER = "[]{}"; | |
| 14 | + var SPACE_CHAR_REGEX = /\s/; | |
| 15 | + | |
| 16 | + var Pos = CodeMirror.Pos; | |
| 17 | + | |
| 18 | + CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) { | |
| 19 | + if (old != CodeMirror.Init && old) | |
| 20 | + cm.removeKeyMap("autoCloseBrackets"); | |
| 21 | + if (!val) return; | |
| 22 | + var pairs = DEFAULT_BRACKETS, explode = DEFAULT_EXPLODE_ON_ENTER; | |
| 23 | + if (typeof val == "string") pairs = val; | |
| 24 | + else if (typeof val == "object") { | |
| 25 | + if (val.pairs != null) pairs = val.pairs; | |
| 26 | + if (val.explode != null) explode = val.explode; | |
| 27 | + } | |
| 28 | + var map = buildKeymap(pairs); | |
| 29 | + if (explode) map.Enter = buildExplodeHandler(explode); | |
| 30 | + cm.addKeyMap(map); | |
| 31 | + }); | |
| 32 | + | |
| 33 | + function charsAround(cm, pos) { | |
| 34 | + var str = cm.getRange(Pos(pos.line, pos.ch - 1), | |
| 35 | + Pos(pos.line, pos.ch + 1)); | |
| 36 | + return str.length == 2 ? str : null; | |
| 37 | + } | |
| 38 | + | |
| 39 | + // Project the token type that will exists after the given char is | |
| 40 | + // typed, and use it to determine whether it would cause the start | |
| 41 | + // of a string token. | |
| 42 | + function enteringString(cm, pos, ch) { | |
| 43 | + var line = cm.getLine(pos.line); | |
| 44 | + var token = cm.getTokenAt(pos); | |
| 45 | + if (/\bstring2?\b/.test(token.type)) return false; | |
| 46 | + var stream = new CodeMirror.StringStream(line.slice(0, pos.ch) + ch + line.slice(pos.ch), 4); | |
| 47 | + stream.pos = stream.start = token.start; | |
| 48 | + for (;;) { | |
| 49 | + var type1 = cm.getMode().token(stream, token.state); | |
| 50 | + if (stream.pos >= pos.ch + 1) return /\bstring2?\b/.test(type1); | |
| 51 | + stream.start = stream.pos; | |
| 52 | + } | |
| 53 | + } | |
| 54 | + | |
| 55 | + function buildKeymap(pairs) { | |
| 56 | + var map = { | |
| 57 | + name : "autoCloseBrackets", | |
| 58 | + Backspace: function(cm) { | |
| 59 | + if (cm.getOption("disableInput")) return CodeMirror.Pass; | |
| 60 | + var ranges = cm.listSelections(); | |
| 61 | + for (var i = 0; i < ranges.length; i++) { | |
| 62 | + if (!ranges[i].empty()) return CodeMirror.Pass; | |
| 63 | + var around = charsAround(cm, ranges[i].head); | |
| 64 | + if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass; | |
| 65 | + } | |
| 66 | + for (var i = ranges.length - 1; i >= 0; i--) { | |
| 67 | + var cur = ranges[i].head; | |
| 68 | + cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1)); | |
| 69 | + } | |
| 70 | + } | |
| 71 | + }; | |
| 72 | + var closingBrackets = ""; | |
| 73 | + for (var i = 0; i < pairs.length; i += 2) (function(left, right) { | |
| 74 | + if (left != right) closingBrackets += right; | |
| 75 | + map["'" + left + "'"] = function(cm) { | |
| 76 | + if (cm.getOption("disableInput")) return CodeMirror.Pass; | |
| 77 | + var ranges = cm.listSelections(), type, next; | |
| 78 | + for (var i = 0; i < ranges.length; i++) { | |
| 79 | + var range = ranges[i], cur = range.head, curType; | |
| 80 | + var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1)); | |
| 81 | + if (!range.empty()) | |
| 82 | + curType = "surround"; | |
| 83 | + else if (left == right && next == right) { | |
| 84 | + if (cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == left + left + left) | |
| 85 | + curType = "skipThree"; | |
| 86 | + else | |
| 87 | + curType = "skip"; | |
| 88 | + } else if (left == right && cur.ch > 1 && | |
| 89 | + cm.getRange(Pos(cur.line, cur.ch - 2), cur) == left + left && | |
| 90 | + (cur.ch <= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != left)) | |
| 91 | + curType = "addFour"; | |
| 92 | + else if (left == '"' || left == "'") { | |
| 93 | + if (!CodeMirror.isWordChar(next) && enteringString(cm, cur, left)) curType = "both"; | |
| 94 | + else return CodeMirror.Pass; | |
| 95 | + } else if (cm.getLine(cur.line).length == cur.ch || closingBrackets.indexOf(next) >= 0 || SPACE_CHAR_REGEX.test(next)) | |
| 96 | + curType = "both"; | |
| 97 | + else | |
| 98 | + return CodeMirror.Pass; | |
| 99 | + if (!type) type = curType; | |
| 100 | + else if (type != curType) return CodeMirror.Pass; | |
| 101 | + } | |
| 102 | + | |
| 103 | + cm.operation(function() { | |
| 104 | + if (type == "skip") { | |
| 105 | + cm.execCommand("goCharRight"); | |
| 106 | + } else if (type == "skipThree") { | |
| 107 | + for (var i = 0; i < 3; i++) | |
| 108 | + cm.execCommand("goCharRight"); | |
| 109 | + } else if (type == "surround") { | |
| 110 | + var sels = cm.getSelections(); | |
| 111 | + for (var i = 0; i < sels.length; i++) | |
| 112 | + sels[i] = left + sels[i] + right; | |
| 113 | + cm.replaceSelections(sels, "around"); | |
| 114 | + } else if (type == "both") { | |
| 115 | + cm.replaceSelection(left + right, null); | |
| 116 | + cm.execCommand("goCharLeft"); | |
| 117 | + } else if (type == "addFour") { | |
| 118 | + cm.replaceSelection(left + left + left + left, "before"); | |
| 119 | + cm.execCommand("goCharRight"); | |
| 120 | + } | |
| 121 | + }); | |
| 122 | + }; | |
| 123 | + if (left != right) map["'" + right + "'"] = function(cm) { | |
| 124 | + var ranges = cm.listSelections(); | |
| 125 | + for (var i = 0; i < ranges.length; i++) { | |
| 126 | + var range = ranges[i]; | |
| 127 | + if (!range.empty() || | |
| 128 | + cm.getRange(range.head, Pos(range.head.line, range.head.ch + 1)) != right) | |
| 129 | + return CodeMirror.Pass; | |
| 130 | + } | |
| 131 | + cm.execCommand("goCharRight"); | |
| 132 | + }; | |
| 133 | + })(pairs.charAt(i), pairs.charAt(i + 1)); | |
| 134 | + return map; | |
| 135 | + } | |
| 136 | + | |
| 137 | + function buildExplodeHandler(pairs) { | |
| 138 | + return function(cm) { | |
| 139 | + if (cm.getOption("disableInput")) return CodeMirror.Pass; | |
| 140 | + var ranges = cm.listSelections(); | |
| 141 | + for (var i = 0; i < ranges.length; i++) { | |
| 142 | + if (!ranges[i].empty()) return CodeMirror.Pass; | |
| 143 | + var around = charsAround(cm, ranges[i].head); | |
| 144 | + if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass; | |
| 145 | + } | |
| 146 | + cm.operation(function() { | |
| 147 | + cm.replaceSelection("\n\n", null); | |
| 148 | + cm.execCommand("goCharLeft"); | |
| 149 | + ranges = cm.listSelections(); | |
| 150 | + for (var i = 0; i < ranges.length; i++) { | |
| 151 | + var line = ranges[i].head.line; | |
| 152 | + cm.indentLine(line, null, true); | |
| 153 | + cm.indentLine(line + 1, null, true); | |
| 154 | + } | |
| 155 | + }); | |
| 156 | + }; | |
| 157 | + } | |
| 158 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,159 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +/** | |
| 5 | + * Tag-closer extension for CodeMirror. | |
| 6 | + * | |
| 7 | + * This extension adds an "autoCloseTags" option that can be set to | |
| 8 | + * either true to get the default behavior, or an object to further | |
| 9 | + * configure its behavior. | |
| 10 | + * | |
| 11 | + * These are supported options: | |
| 12 | + * | |
| 13 | + * `whenClosing` (default true) | |
| 14 | + * Whether to autoclose when the '/' of a closing tag is typed. | |
| 15 | + * `whenOpening` (default true) | |
| 16 | + * Whether to autoclose the tag when the final '>' of an opening | |
| 17 | + * tag is typed. | |
| 18 | + * `dontCloseTags` (default is empty tags for HTML, none for XML) | |
| 19 | + * An array of tag names that should not be autoclosed. | |
| 20 | + * `indentTags` (default is block tags for HTML, none for XML) | |
| 21 | + * An array of tag names that should, when opened, cause a | |
| 22 | + * blank line to be added inside the tag, and the blank line and | |
| 23 | + * closing line to be indented. | |
| 24 | + * | |
| 25 | + * See demos/closetag.html for a usage example. | |
| 26 | + */ | |
| 27 | + | |
| 28 | +(function(mod) { | |
| 29 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 30 | + mod(require("../../lib/codemirror"), require("../fold/xml-fold")); | |
| 31 | + else if (typeof define == "function" && define.amd) // AMD | |
| 32 | + define(["../../lib/codemirror", "../fold/xml-fold"], mod); | |
| 33 | + else // Plain browser env | |
| 34 | + mod(CodeMirror); | |
| 35 | +})(function(CodeMirror) { | |
| 36 | + CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) { | |
| 37 | + if (old != CodeMirror.Init && old) | |
| 38 | + cm.removeKeyMap("autoCloseTags"); | |
| 39 | + if (!val) return; | |
| 40 | + var map = {name: "autoCloseTags"}; | |
| 41 | + if (typeof val != "object" || val.whenClosing) | |
| 42 | + map["'/'"] = function(cm) { return autoCloseSlash(cm); }; | |
| 43 | + if (typeof val != "object" || val.whenOpening) | |
| 44 | + map["'>'"] = function(cm) { return autoCloseGT(cm); }; | |
| 45 | + cm.addKeyMap(map); | |
| 46 | + }); | |
| 47 | + | |
| 48 | + var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", | |
| 49 | + "source", "track", "wbr"]; | |
| 50 | + var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4", | |
| 51 | + "h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"]; | |
| 52 | + | |
| 53 | + function autoCloseGT(cm) { | |
| 54 | + if (cm.getOption("disableInput")) return CodeMirror.Pass; | |
| 55 | + var ranges = cm.listSelections(), replacements = []; | |
| 56 | + for (var i = 0; i < ranges.length; i++) { | |
| 57 | + if (!ranges[i].empty()) return CodeMirror.Pass; | |
| 58 | + var pos = ranges[i].head, tok = cm.getTokenAt(pos); | |
| 59 | + var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; | |
| 60 | + if (inner.mode.name != "xml" || !state.tagName) return CodeMirror.Pass; | |
| 61 | + | |
| 62 | + var opt = cm.getOption("autoCloseTags"), html = inner.mode.configuration == "html"; | |
| 63 | + var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose); | |
| 64 | + var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent); | |
| 65 | + | |
| 66 | + var tagName = state.tagName; | |
| 67 | + if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch); | |
| 68 | + var lowerTagName = tagName.toLowerCase(); | |
| 69 | + // Don't process the '>' at the end of an end-tag or self-closing tag | |
| 70 | + if (!tagName || | |
| 71 | + tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) || | |
| 72 | + tok.type == "tag" && state.type == "closeTag" || | |
| 73 | + tok.string.indexOf("/") == (tok.string.length - 1) || // match something like <someTagName /> | |
| 74 | + dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 || | |
| 75 | + closingTagExists(cm, tagName, pos, state, true)) | |
| 76 | + return CodeMirror.Pass; | |
| 77 | + | |
| 78 | + var indent = indentTags && indexOf(indentTags, lowerTagName) > -1; | |
| 79 | + replacements[i] = {indent: indent, | |
| 80 | + text: ">" + (indent ? "\n\n" : "") + "</" + tagName + ">", | |
| 81 | + newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)}; | |
| 82 | + } | |
| 83 | + | |
| 84 | + for (var i = ranges.length - 1; i >= 0; i--) { | |
| 85 | + var info = replacements[i]; | |
| 86 | + cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert"); | |
| 87 | + var sel = cm.listSelections().slice(0); | |
| 88 | + sel[i] = {head: info.newPos, anchor: info.newPos}; | |
| 89 | + cm.setSelections(sel); | |
| 90 | + if (info.indent) { | |
| 91 | + cm.indentLine(info.newPos.line, null, true); | |
| 92 | + cm.indentLine(info.newPos.line + 1, null, true); | |
| 93 | + } | |
| 94 | + } | |
| 95 | + } | |
| 96 | + | |
| 97 | + function autoCloseSlash(cm) { | |
| 98 | + if (cm.getOption("disableInput")) return CodeMirror.Pass; | |
| 99 | + var ranges = cm.listSelections(), replacements = []; | |
| 100 | + for (var i = 0; i < ranges.length; i++) { | |
| 101 | + if (!ranges[i].empty()) return CodeMirror.Pass; | |
| 102 | + var pos = ranges[i].head, tok = cm.getTokenAt(pos); | |
| 103 | + var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; | |
| 104 | + if (tok.type == "string" || tok.string.charAt(0) != "<" || | |
| 105 | + tok.start != pos.ch - 1) | |
| 106 | + return CodeMirror.Pass; | |
| 107 | + // Kludge to get around the fact that we are not in XML mode | |
| 108 | + // when completing in JS/CSS snippet in htmlmixed mode. Does not | |
| 109 | + // work for other XML embedded languages (there is no general | |
| 110 | + // way to go from a mixed mode to its current XML state). | |
| 111 | + if (inner.mode.name != "xml") { | |
| 112 | + if (cm.getMode().name == "htmlmixed" && inner.mode.name == "javascript") | |
| 113 | + replacements[i] = "/script>"; | |
| 114 | + else if (cm.getMode().name == "htmlmixed" && inner.mode.name == "css") | |
| 115 | + replacements[i] = "/style>"; | |
| 116 | + else | |
| 117 | + return CodeMirror.Pass; | |
| 118 | + } else { | |
| 119 | + if (!state.context || !state.context.tagName || | |
| 120 | + closingTagExists(cm, state.context.tagName, pos, state)) | |
| 121 | + return CodeMirror.Pass; | |
| 122 | + replacements[i] = "/" + state.context.tagName + ">"; | |
| 123 | + } | |
| 124 | + } | |
| 125 | + cm.replaceSelections(replacements); | |
| 126 | + ranges = cm.listSelections(); | |
| 127 | + for (var i = 0; i < ranges.length; i++) | |
| 128 | + if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line) | |
| 129 | + cm.indentLine(ranges[i].head.line); | |
| 130 | + } | |
| 131 | + | |
| 132 | + function indexOf(collection, elt) { | |
| 133 | + if (collection.indexOf) return collection.indexOf(elt); | |
| 134 | + for (var i = 0, e = collection.length; i < e; ++i) | |
| 135 | + if (collection[i] == elt) return i; | |
| 136 | + return -1; | |
| 137 | + } | |
| 138 | + | |
| 139 | + // If xml-fold is loaded, we use its functionality to try and verify | |
| 140 | + // whether a given tag is actually unclosed. | |
| 141 | + function closingTagExists(cm, tagName, pos, state, newTag) { | |
| 142 | + if (!CodeMirror.scanForClosingTag) return false; | |
| 143 | + var end = Math.min(cm.lastLine() + 1, pos.line + 500); | |
| 144 | + var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end); | |
| 145 | + if (!nextClose || nextClose.tag != tagName) return false; | |
| 146 | + var cx = state.context; | |
| 147 | + // If the immediate wrapping context contains onCx instances of | |
| 148 | + // the same tag, a closing tag only exists if there are at least | |
| 149 | + // that many closing tags of that type following. | |
| 150 | + for (var onCx = newTag ? 1 : 0; cx && cx.tagName == tagName; cx = cx.prev) ++onCx; | |
| 151 | + pos = nextClose.to; | |
| 152 | + for (var i = 1; i < onCx; i++) { | |
| 153 | + var next = CodeMirror.scanForClosingTag(cm, pos, null, end); | |
| 154 | + if (!next || next.tag != tagName) return false; | |
| 155 | + pos = next.to; | |
| 156 | + } | |
| 157 | + return true; | |
| 158 | + } | |
| 159 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,38 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + "use strict"; | |
| 13 | + | |
| 14 | + var listRE = /^(\s*)([*+-]|(\d+)\.)(\s+)/, | |
| 15 | + unorderedBullets = "*+-"; | |
| 16 | + | |
| 17 | + CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) { | |
| 18 | + if (cm.getOption("disableInput")) return CodeMirror.Pass; | |
| 19 | + var ranges = cm.listSelections(), replacements = []; | |
| 20 | + for (var i = 0; i < ranges.length; i++) { | |
| 21 | + var pos = ranges[i].head, match; | |
| 22 | + var inList = cm.getStateAfter(pos.line).list !== false; | |
| 23 | + | |
| 24 | + if (!ranges[i].empty() || !inList || !(match = cm.getLine(pos.line).match(listRE))) { | |
| 25 | + cm.execCommand("newlineAndIndent"); | |
| 26 | + return; | |
| 27 | + } | |
| 28 | + var indent = match[1], after = match[4]; | |
| 29 | + var bullet = unorderedBullets.indexOf(match[2]) >= 0 | |
| 30 | + ? match[2] | |
| 31 | + : (parseInt(match[3], 10) + 1) + "."; | |
| 32 | + | |
| 33 | + replacements[i] = "\n" + indent + bullet + after; | |
| 34 | + } | |
| 35 | + | |
| 36 | + cm.replaceSelections(replacements); | |
| 37 | + }; | |
| 38 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,120 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + var ie_lt8 = /MSIE \d/.test(navigator.userAgent) && | |
| 13 | + (document.documentMode == null || document.documentMode < 8); | |
| 14 | + | |
| 15 | + var Pos = CodeMirror.Pos; | |
| 16 | + | |
| 17 | + var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"}; | |
| 18 | + | |
| 19 | + function findMatchingBracket(cm, where, strict, config) { | |
| 20 | + var line = cm.getLineHandle(where.line), pos = where.ch - 1; | |
| 21 | + var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)]; | |
| 22 | + if (!match) return null; | |
| 23 | + var dir = match.charAt(1) == ">" ? 1 : -1; | |
| 24 | + if (strict && (dir > 0) != (pos == where.ch)) return null; | |
| 25 | + var style = cm.getTokenTypeAt(Pos(where.line, pos + 1)); | |
| 26 | + | |
| 27 | + var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config); | |
| 28 | + if (found == null) return null; | |
| 29 | + return {from: Pos(where.line, pos), to: found && found.pos, | |
| 30 | + match: found && found.ch == match.charAt(0), forward: dir > 0}; | |
| 31 | + } | |
| 32 | + | |
| 33 | + // bracketRegex is used to specify which type of bracket to scan | |
| 34 | + // should be a regexp, e.g. /[[\]]/ | |
| 35 | + // | |
| 36 | + // Note: If "where" is on an open bracket, then this bracket is ignored. | |
| 37 | + // | |
| 38 | + // Returns false when no bracket was found, null when it reached | |
| 39 | + // maxScanLines and gave up | |
| 40 | + function scanForBracket(cm, where, dir, style, config) { | |
| 41 | + var maxScanLen = (config && config.maxScanLineLength) || 10000; | |
| 42 | + var maxScanLines = (config && config.maxScanLines) || 1000; | |
| 43 | + | |
| 44 | + var stack = []; | |
| 45 | + var re = config && config.bracketRegex ? config.bracketRegex : /[(){}[\]]/; | |
| 46 | + var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1) | |
| 47 | + : Math.max(cm.firstLine() - 1, where.line - maxScanLines); | |
| 48 | + for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) { | |
| 49 | + var line = cm.getLine(lineNo); | |
| 50 | + if (!line) continue; | |
| 51 | + var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1; | |
| 52 | + if (line.length > maxScanLen) continue; | |
| 53 | + if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0); | |
| 54 | + for (; pos != end; pos += dir) { | |
| 55 | + var ch = line.charAt(pos); | |
| 56 | + if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) { | |
| 57 | + var match = matching[ch]; | |
| 58 | + if ((match.charAt(1) == ">") == (dir > 0)) stack.push(ch); | |
| 59 | + else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch}; | |
| 60 | + else stack.pop(); | |
| 61 | + } | |
| 62 | + } | |
| 63 | + } | |
| 64 | + return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null; | |
| 65 | + } | |
| 66 | + | |
| 67 | + function matchBrackets(cm, autoclear, config) { | |
| 68 | + // Disable brace matching in long lines, since it'll cause hugely slow updates | |
| 69 | + var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000; | |
| 70 | + var marks = [], ranges = cm.listSelections(); | |
| 71 | + for (var i = 0; i < ranges.length; i++) { | |
| 72 | + var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, false, config); | |
| 73 | + if (match && cm.getLine(match.from.line).length <= maxHighlightLen) { | |
| 74 | + var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket"; | |
| 75 | + marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style})); | |
| 76 | + if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen) | |
| 77 | + marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style})); | |
| 78 | + } | |
| 79 | + } | |
| 80 | + | |
| 81 | + if (marks.length) { | |
| 82 | + // Kludge to work around the IE bug from issue #1193, where text | |
| 83 | + // input stops going to the textare whever this fires. | |
| 84 | + if (ie_lt8 && cm.state.focused) cm.display.input.focus(); | |
| 85 | + | |
| 86 | + var clear = function() { | |
| 87 | + cm.operation(function() { | |
| 88 | + for (var i = 0; i < marks.length; i++) marks[i].clear(); | |
| 89 | + }); | |
| 90 | + }; | |
| 91 | + if (autoclear) setTimeout(clear, 800); | |
| 92 | + else return clear; | |
| 93 | + } | |
| 94 | + } | |
| 95 | + | |
| 96 | + var currentlyHighlighted = null; | |
| 97 | + function doMatchBrackets(cm) { | |
| 98 | + cm.operation(function() { | |
| 99 | + if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;} | |
| 100 | + currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets); | |
| 101 | + }); | |
| 102 | + } | |
| 103 | + | |
| 104 | + CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) { | |
| 105 | + if (old && old != CodeMirror.Init) | |
| 106 | + cm.off("cursorActivity", doMatchBrackets); | |
| 107 | + if (val) { | |
| 108 | + cm.state.matchBrackets = typeof val == "object" ? val : {}; | |
| 109 | + cm.on("cursorActivity", doMatchBrackets); | |
| 110 | + } | |
| 111 | + }); | |
| 112 | + | |
| 113 | + CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);}); | |
| 114 | + CodeMirror.defineExtension("findMatchingBracket", function(pos, strict, config){ | |
| 115 | + return findMatchingBracket(this, pos, strict, config); | |
| 116 | + }); | |
| 117 | + CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){ | |
| 118 | + return scanForBracket(this, pos, dir, style, config); | |
| 119 | + }); | |
| 120 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,66 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror"), require("../fold/xml-fold")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror", "../fold/xml-fold"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + "use strict"; | |
| 13 | + | |
| 14 | + CodeMirror.defineOption("matchTags", false, function(cm, val, old) { | |
| 15 | + if (old && old != CodeMirror.Init) { | |
| 16 | + cm.off("cursorActivity", doMatchTags); | |
| 17 | + cm.off("viewportChange", maybeUpdateMatch); | |
| 18 | + clear(cm); | |
| 19 | + } | |
| 20 | + if (val) { | |
| 21 | + cm.state.matchBothTags = typeof val == "object" && val.bothTags; | |
| 22 | + cm.on("cursorActivity", doMatchTags); | |
| 23 | + cm.on("viewportChange", maybeUpdateMatch); | |
| 24 | + doMatchTags(cm); | |
| 25 | + } | |
| 26 | + }); | |
| 27 | + | |
| 28 | + function clear(cm) { | |
| 29 | + if (cm.state.tagHit) cm.state.tagHit.clear(); | |
| 30 | + if (cm.state.tagOther) cm.state.tagOther.clear(); | |
| 31 | + cm.state.tagHit = cm.state.tagOther = null; | |
| 32 | + } | |
| 33 | + | |
| 34 | + function doMatchTags(cm) { | |
| 35 | + cm.state.failedTagMatch = false; | |
| 36 | + cm.operation(function() { | |
| 37 | + clear(cm); | |
| 38 | + if (cm.somethingSelected()) return; | |
| 39 | + var cur = cm.getCursor(), range = cm.getViewport(); | |
| 40 | + range.from = Math.min(range.from, cur.line); range.to = Math.max(cur.line + 1, range.to); | |
| 41 | + var match = CodeMirror.findMatchingTag(cm, cur, range); | |
| 42 | + if (!match) return; | |
| 43 | + if (cm.state.matchBothTags) { | |
| 44 | + var hit = match.at == "open" ? match.open : match.close; | |
| 45 | + if (hit) cm.state.tagHit = cm.markText(hit.from, hit.to, {className: "CodeMirror-matchingtag"}); | |
| 46 | + } | |
| 47 | + var other = match.at == "close" ? match.open : match.close; | |
| 48 | + if (other) | |
| 49 | + cm.state.tagOther = cm.markText(other.from, other.to, {className: "CodeMirror-matchingtag"}); | |
| 50 | + else | |
| 51 | + cm.state.failedTagMatch = true; | |
| 52 | + }); | |
| 53 | + } | |
| 54 | + | |
| 55 | + function maybeUpdateMatch(cm) { | |
| 56 | + if (cm.state.failedTagMatch) doMatchTags(cm); | |
| 57 | + } | |
| 58 | + | |
| 59 | + CodeMirror.commands.toMatchingTag = function(cm) { | |
| 60 | + var found = CodeMirror.findMatchingTag(cm, cm.getCursor()); | |
| 61 | + if (found) { | |
| 62 | + var other = found.at == "close" ? found.open : found.close; | |
| 63 | + if (other) cm.extendSelection(other.to, other.from); | |
| 64 | + } | |
| 65 | + }; | |
| 66 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,27 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + CodeMirror.defineOption("showTrailingSpace", false, function(cm, val, prev) { | |
| 13 | + if (prev == CodeMirror.Init) prev = false; | |
| 14 | + if (prev && !val) | |
| 15 | + cm.removeOverlay("trailingspace"); | |
| 16 | + else if (!prev && val) | |
| 17 | + cm.addOverlay({ | |
| 18 | + token: function(stream) { | |
| 19 | + for (var l = stream.string.length, i = l; i && /\s/.test(stream.string.charAt(i - 1)); --i) {} | |
| 20 | + if (i > stream.pos) { stream.pos = i; return null; } | |
| 21 | + stream.pos = l; | |
| 22 | + return "trailingspace"; | |
| 23 | + }, | |
| 24 | + name: "trailingspace" | |
| 25 | + }); | |
| 26 | + }); | |
| 27 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,105 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | +"use strict"; | |
| 13 | + | |
| 14 | +CodeMirror.registerHelper("fold", "brace", function(cm, start) { | |
| 15 | + var line = start.line, lineText = cm.getLine(line); | |
| 16 | + var startCh, tokenType; | |
| 17 | + | |
| 18 | + function findOpening(openCh) { | |
| 19 | + for (var at = start.ch, pass = 0;;) { | |
| 20 | + var found = at <= 0 ? -1 : lineText.lastIndexOf(openCh, at - 1); | |
| 21 | + if (found == -1) { | |
| 22 | + if (pass == 1) break; | |
| 23 | + pass = 1; | |
| 24 | + at = lineText.length; | |
| 25 | + continue; | |
| 26 | + } | |
| 27 | + if (pass == 1 && found < start.ch) break; | |
| 28 | + tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1)); | |
| 29 | + if (!/^(comment|string)/.test(tokenType)) return found + 1; | |
| 30 | + at = found - 1; | |
| 31 | + } | |
| 32 | + } | |
| 33 | + | |
| 34 | + var startToken = "{", endToken = "}", startCh = findOpening("{"); | |
| 35 | + if (startCh == null) { | |
| 36 | + startToken = "[", endToken = "]"; | |
| 37 | + startCh = findOpening("["); | |
| 38 | + } | |
| 39 | + | |
| 40 | + if (startCh == null) return; | |
| 41 | + var count = 1, lastLine = cm.lastLine(), end, endCh; | |
| 42 | + outer: for (var i = line; i <= lastLine; ++i) { | |
| 43 | + var text = cm.getLine(i), pos = i == line ? startCh : 0; | |
| 44 | + for (;;) { | |
| 45 | + var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos); | |
| 46 | + if (nextOpen < 0) nextOpen = text.length; | |
| 47 | + if (nextClose < 0) nextClose = text.length; | |
| 48 | + pos = Math.min(nextOpen, nextClose); | |
| 49 | + if (pos == text.length) break; | |
| 50 | + if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == tokenType) { | |
| 51 | + if (pos == nextOpen) ++count; | |
| 52 | + else if (!--count) { end = i; endCh = pos; break outer; } | |
| 53 | + } | |
| 54 | + ++pos; | |
| 55 | + } | |
| 56 | + } | |
| 57 | + if (end == null || line == end && endCh == startCh) return; | |
| 58 | + return {from: CodeMirror.Pos(line, startCh), | |
| 59 | + to: CodeMirror.Pos(end, endCh)}; | |
| 60 | +}); | |
| 61 | + | |
| 62 | +CodeMirror.registerHelper("fold", "import", function(cm, start) { | |
| 63 | + function hasImport(line) { | |
| 64 | + if (line < cm.firstLine() || line > cm.lastLine()) return null; | |
| 65 | + var start = cm.getTokenAt(CodeMirror.Pos(line, 1)); | |
| 66 | + if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1)); | |
| 67 | + if (start.type != "keyword" || start.string != "import") return null; | |
| 68 | + // Now find closing semicolon, return its position | |
| 69 | + for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) { | |
| 70 | + var text = cm.getLine(i), semi = text.indexOf(";"); | |
| 71 | + if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)}; | |
| 72 | + } | |
| 73 | + } | |
| 74 | + | |
| 75 | + var start = start.line, has = hasImport(start), prev; | |
| 76 | + if (!has || hasImport(start - 1) || ((prev = hasImport(start - 2)) && prev.end.line == start - 1)) | |
| 77 | + return null; | |
| 78 | + for (var end = has.end;;) { | |
| 79 | + var next = hasImport(end.line + 1); | |
| 80 | + if (next == null) break; | |
| 81 | + end = next.end; | |
| 82 | + } | |
| 83 | + return {from: cm.clipPos(CodeMirror.Pos(start, has.startCh + 1)), to: end}; | |
| 84 | +}); | |
| 85 | + | |
| 86 | +CodeMirror.registerHelper("fold", "include", function(cm, start) { | |
| 87 | + function hasInclude(line) { | |
| 88 | + if (line < cm.firstLine() || line > cm.lastLine()) return null; | |
| 89 | + var start = cm.getTokenAt(CodeMirror.Pos(line, 1)); | |
| 90 | + if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1)); | |
| 91 | + if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8; | |
| 92 | + } | |
| 93 | + | |
| 94 | + var start = start.line, has = hasInclude(start); | |
| 95 | + if (has == null || hasInclude(start - 1) != null) return null; | |
| 96 | + for (var end = start;;) { | |
| 97 | + var next = hasInclude(end + 1); | |
| 98 | + if (next == null) break; | |
| 99 | + ++end; | |
| 100 | + } | |
| 101 | + return {from: CodeMirror.Pos(start, has + 1), | |
| 102 | + to: cm.clipPos(CodeMirror.Pos(end))}; | |
| 103 | +}); | |
| 104 | + | |
| 105 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,57 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | +"use strict"; | |
| 13 | + | |
| 14 | +CodeMirror.registerGlobalHelper("fold", "comment", function(mode) { | |
| 15 | + return mode.blockCommentStart && mode.blockCommentEnd; | |
| 16 | +}, function(cm, start) { | |
| 17 | + var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd; | |
| 18 | + if (!startToken || !endToken) return; | |
| 19 | + var line = start.line, lineText = cm.getLine(line); | |
| 20 | + | |
| 21 | + var startCh; | |
| 22 | + for (var at = start.ch, pass = 0;;) { | |
| 23 | + var found = at <= 0 ? -1 : lineText.lastIndexOf(startToken, at - 1); | |
| 24 | + if (found == -1) { | |
| 25 | + if (pass == 1) return; | |
| 26 | + pass = 1; | |
| 27 | + at = lineText.length; | |
| 28 | + continue; | |
| 29 | + } | |
| 30 | + if (pass == 1 && found < start.ch) return; | |
| 31 | + if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1)))) { | |
| 32 | + startCh = found + startToken.length; | |
| 33 | + break; | |
| 34 | + } | |
| 35 | + at = found - 1; | |
| 36 | + } | |
| 37 | + | |
| 38 | + var depth = 1, lastLine = cm.lastLine(), end, endCh; | |
| 39 | + outer: for (var i = line; i <= lastLine; ++i) { | |
| 40 | + var text = cm.getLine(i), pos = i == line ? startCh : 0; | |
| 41 | + for (;;) { | |
| 42 | + var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos); | |
| 43 | + if (nextOpen < 0) nextOpen = text.length; | |
| 44 | + if (nextClose < 0) nextClose = text.length; | |
| 45 | + pos = Math.min(nextOpen, nextClose); | |
| 46 | + if (pos == text.length) break; | |
| 47 | + if (pos == nextOpen) ++depth; | |
| 48 | + else if (!--depth) { end = i; endCh = pos; break outer; } | |
| 49 | + ++pos; | |
| 50 | + } | |
| 51 | + } | |
| 52 | + if (end == null || line == end && endCh == startCh) return; | |
| 53 | + return {from: CodeMirror.Pos(line, startCh), | |
| 54 | + to: CodeMirror.Pos(end, endCh)}; | |
| 55 | +}); | |
| 56 | + | |
| 57 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,145 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + "use strict"; | |
| 13 | + | |
| 14 | + function doFold(cm, pos, options, force) { | |
| 15 | + if (options && options.call) { | |
| 16 | + var finder = options; | |
| 17 | + options = null; | |
| 18 | + } else { | |
| 19 | + var finder = getOption(cm, options, "rangeFinder"); | |
| 20 | + } | |
| 21 | + if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0); | |
| 22 | + var minSize = getOption(cm, options, "minFoldSize"); | |
| 23 | + | |
| 24 | + function getRange(allowFolded) { | |
| 25 | + var range = finder(cm, pos); | |
| 26 | + if (!range || range.to.line - range.from.line < minSize) return null; | |
| 27 | + var marks = cm.findMarksAt(range.from); | |
| 28 | + for (var i = 0; i < marks.length; ++i) { | |
| 29 | + if (marks[i].__isFold && force !== "fold") { | |
| 30 | + if (!allowFolded) return null; | |
| 31 | + range.cleared = true; | |
| 32 | + marks[i].clear(); | |
| 33 | + } | |
| 34 | + } | |
| 35 | + return range; | |
| 36 | + } | |
| 37 | + | |
| 38 | + var range = getRange(true); | |
| 39 | + if (getOption(cm, options, "scanUp")) while (!range && pos.line > cm.firstLine()) { | |
| 40 | + pos = CodeMirror.Pos(pos.line - 1, 0); | |
| 41 | + range = getRange(false); | |
| 42 | + } | |
| 43 | + if (!range || range.cleared || force === "unfold") return; | |
| 44 | + | |
| 45 | + var myWidget = makeWidget(cm, options); | |
| 46 | + CodeMirror.on(myWidget, "mousedown", function(e) { | |
| 47 | + myRange.clear(); | |
| 48 | + CodeMirror.e_preventDefault(e); | |
| 49 | + }); | |
| 50 | + var myRange = cm.markText(range.from, range.to, { | |
| 51 | + replacedWith: myWidget, | |
| 52 | + clearOnEnter: true, | |
| 53 | + __isFold: true | |
| 54 | + }); | |
| 55 | + myRange.on("clear", function(from, to) { | |
| 56 | + CodeMirror.signal(cm, "unfold", cm, from, to); | |
| 57 | + }); | |
| 58 | + CodeMirror.signal(cm, "fold", cm, range.from, range.to); | |
| 59 | + } | |
| 60 | + | |
| 61 | + function makeWidget(cm, options) { | |
| 62 | + var widget = getOption(cm, options, "widget"); | |
| 63 | + if (typeof widget == "string") { | |
| 64 | + var text = document.createTextNode(widget); | |
| 65 | + widget = document.createElement("span"); | |
| 66 | + widget.appendChild(text); | |
| 67 | + widget.className = "CodeMirror-foldmarker"; | |
| 68 | + } | |
| 69 | + return widget; | |
| 70 | + } | |
| 71 | + | |
| 72 | + // Clumsy backwards-compatible interface | |
| 73 | + CodeMirror.newFoldFunction = function(rangeFinder, widget) { | |
| 74 | + return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); }; | |
| 75 | + }; | |
| 76 | + | |
| 77 | + // New-style interface | |
| 78 | + CodeMirror.defineExtension("foldCode", function(pos, options, force) { | |
| 79 | + doFold(this, pos, options, force); | |
| 80 | + }); | |
| 81 | + | |
| 82 | + CodeMirror.defineExtension("isFolded", function(pos) { | |
| 83 | + var marks = this.findMarksAt(pos); | |
| 84 | + for (var i = 0; i < marks.length; ++i) | |
| 85 | + if (marks[i].__isFold) return true; | |
| 86 | + }); | |
| 87 | + | |
| 88 | + CodeMirror.commands.toggleFold = function(cm) { | |
| 89 | + cm.foldCode(cm.getCursor()); | |
| 90 | + }; | |
| 91 | + CodeMirror.commands.fold = function(cm) { | |
| 92 | + cm.foldCode(cm.getCursor(), null, "fold"); | |
| 93 | + }; | |
| 94 | + CodeMirror.commands.unfold = function(cm) { | |
| 95 | + cm.foldCode(cm.getCursor(), null, "unfold"); | |
| 96 | + }; | |
| 97 | + CodeMirror.commands.foldAll = function(cm) { | |
| 98 | + cm.operation(function() { | |
| 99 | + for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++) | |
| 100 | + cm.foldCode(CodeMirror.Pos(i, 0), null, "fold"); | |
| 101 | + }); | |
| 102 | + }; | |
| 103 | + CodeMirror.commands.unfoldAll = function(cm) { | |
| 104 | + cm.operation(function() { | |
| 105 | + for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++) | |
| 106 | + cm.foldCode(CodeMirror.Pos(i, 0), null, "unfold"); | |
| 107 | + }); | |
| 108 | + }; | |
| 109 | + | |
| 110 | + CodeMirror.registerHelper("fold", "combine", function() { | |
| 111 | + var funcs = Array.prototype.slice.call(arguments, 0); | |
| 112 | + return function(cm, start) { | |
| 113 | + for (var i = 0; i < funcs.length; ++i) { | |
| 114 | + var found = funcs[i](cm, start); | |
| 115 | + if (found) return found; | |
| 116 | + } | |
| 117 | + }; | |
| 118 | + }); | |
| 119 | + | |
| 120 | + CodeMirror.registerHelper("fold", "auto", function(cm, start) { | |
| 121 | + var helpers = cm.getHelpers(start, "fold"); | |
| 122 | + for (var i = 0; i < helpers.length; i++) { | |
| 123 | + var cur = helpers[i](cm, start); | |
| 124 | + if (cur) return cur; | |
| 125 | + } | |
| 126 | + }); | |
| 127 | + | |
| 128 | + var defaultOptions = { | |
| 129 | + rangeFinder: CodeMirror.fold.auto, | |
| 130 | + widget: "\u2194", | |
| 131 | + minFoldSize: 0, | |
| 132 | + scanUp: false | |
| 133 | + }; | |
| 134 | + | |
| 135 | + CodeMirror.defineOption("foldOptions", null); | |
| 136 | + | |
| 137 | + function getOption(cm, options, name) { | |
| 138 | + if (options && options[name] !== undefined) | |
| 139 | + return options[name]; | |
| 140 | + var editorOptions = cm.options.foldOptions; | |
| 141 | + if (editorOptions && editorOptions[name] !== undefined) | |
| 142 | + return editorOptions[name]; | |
| 143 | + return defaultOptions[name]; | |
| 144 | + } | |
| 145 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,20 @@ |
| 1 | +.CodeMirror-foldmarker { | |
| 2 | + color: blue; | |
| 3 | + text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px; | |
| 4 | + font-family: arial; | |
| 5 | + line-height: .3; | |
| 6 | + cursor: pointer; | |
| 7 | +} | |
| 8 | +.CodeMirror-foldgutter { | |
| 9 | + width: .7em; | |
| 10 | +} | |
| 11 | +.CodeMirror-foldgutter-open, | |
| 12 | +.CodeMirror-foldgutter-folded { | |
| 13 | + cursor: pointer; | |
| 14 | +} | |
| 15 | +.CodeMirror-foldgutter-open:after { | |
| 16 | + content: "\25BE"; | |
| 17 | +} | |
| 18 | +.CodeMirror-foldgutter-folded:after { | |
| 19 | + content: "\25B8"; | |
| 20 | +} | ... | ... |
| ... | ... | @@ -0,0 +1,134 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror"), require("./foldcode")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror", "./foldcode"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + "use strict"; | |
| 13 | + | |
| 14 | + CodeMirror.defineOption("foldGutter", false, function(cm, val, old) { | |
| 15 | + if (old && old != CodeMirror.Init) { | |
| 16 | + cm.clearGutter(cm.state.foldGutter.options.gutter); | |
| 17 | + cm.state.foldGutter = null; | |
| 18 | + cm.off("gutterClick", onGutterClick); | |
| 19 | + cm.off("change", onChange); | |
| 20 | + cm.off("viewportChange", onViewportChange); | |
| 21 | + cm.off("fold", onFold); | |
| 22 | + cm.off("unfold", onFold); | |
| 23 | + cm.off("swapDoc", updateInViewport); | |
| 24 | + } | |
| 25 | + if (val) { | |
| 26 | + cm.state.foldGutter = new State(parseOptions(val)); | |
| 27 | + updateInViewport(cm); | |
| 28 | + cm.on("gutterClick", onGutterClick); | |
| 29 | + cm.on("change", onChange); | |
| 30 | + cm.on("viewportChange", onViewportChange); | |
| 31 | + cm.on("fold", onFold); | |
| 32 | + cm.on("unfold", onFold); | |
| 33 | + cm.on("swapDoc", updateInViewport); | |
| 34 | + } | |
| 35 | + }); | |
| 36 | + | |
| 37 | + var Pos = CodeMirror.Pos; | |
| 38 | + | |
| 39 | + function State(options) { | |
| 40 | + this.options = options; | |
| 41 | + this.from = this.to = 0; | |
| 42 | + } | |
| 43 | + | |
| 44 | + function parseOptions(opts) { | |
| 45 | + if (opts === true) opts = {}; | |
| 46 | + if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter"; | |
| 47 | + if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open"; | |
| 48 | + if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded"; | |
| 49 | + return opts; | |
| 50 | + } | |
| 51 | + | |
| 52 | + function isFolded(cm, line) { | |
| 53 | + var marks = cm.findMarksAt(Pos(line)); | |
| 54 | + for (var i = 0; i < marks.length; ++i) | |
| 55 | + if (marks[i].__isFold && marks[i].find().from.line == line) return true; | |
| 56 | + } | |
| 57 | + | |
| 58 | + function marker(spec) { | |
| 59 | + if (typeof spec == "string") { | |
| 60 | + var elt = document.createElement("div"); | |
| 61 | + elt.className = spec + " CodeMirror-guttermarker-subtle"; | |
| 62 | + return elt; | |
| 63 | + } else { | |
| 64 | + return spec.cloneNode(true); | |
| 65 | + } | |
| 66 | + } | |
| 67 | + | |
| 68 | + function updateFoldInfo(cm, from, to) { | |
| 69 | + var opts = cm.state.foldGutter.options, cur = from; | |
| 70 | + cm.eachLine(from, to, function(line) { | |
| 71 | + var mark = null; | |
| 72 | + if (isFolded(cm, cur)) { | |
| 73 | + mark = marker(opts.indicatorFolded); | |
| 74 | + } else { | |
| 75 | + var pos = Pos(cur, 0), func = opts.rangeFinder || CodeMirror.fold.auto; | |
| 76 | + var range = func && func(cm, pos); | |
| 77 | + if (range && range.from.line + 1 < range.to.line) | |
| 78 | + mark = marker(opts.indicatorOpen); | |
| 79 | + } | |
| 80 | + cm.setGutterMarker(line, opts.gutter, mark); | |
| 81 | + ++cur; | |
| 82 | + }); | |
| 83 | + } | |
| 84 | + | |
| 85 | + function updateInViewport(cm) { | |
| 86 | + var vp = cm.getViewport(), state = cm.state.foldGutter; | |
| 87 | + if (!state) return; | |
| 88 | + cm.operation(function() { | |
| 89 | + updateFoldInfo(cm, vp.from, vp.to); | |
| 90 | + }); | |
| 91 | + state.from = vp.from; state.to = vp.to; | |
| 92 | + } | |
| 93 | + | |
| 94 | + function onGutterClick(cm, line, gutter) { | |
| 95 | + var opts = cm.state.foldGutter.options; | |
| 96 | + if (gutter != opts.gutter) return; | |
| 97 | + cm.foldCode(Pos(line, 0), opts.rangeFinder); | |
| 98 | + } | |
| 99 | + | |
| 100 | + function onChange(cm) { | |
| 101 | + var state = cm.state.foldGutter, opts = cm.state.foldGutter.options; | |
| 102 | + state.from = state.to = 0; | |
| 103 | + clearTimeout(state.changeUpdate); | |
| 104 | + state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600); | |
| 105 | + } | |
| 106 | + | |
| 107 | + function onViewportChange(cm) { | |
| 108 | + var state = cm.state.foldGutter, opts = cm.state.foldGutter.options; | |
| 109 | + clearTimeout(state.changeUpdate); | |
| 110 | + state.changeUpdate = setTimeout(function() { | |
| 111 | + var vp = cm.getViewport(); | |
| 112 | + if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) { | |
| 113 | + updateInViewport(cm); | |
| 114 | + } else { | |
| 115 | + cm.operation(function() { | |
| 116 | + if (vp.from < state.from) { | |
| 117 | + updateFoldInfo(cm, vp.from, state.from); | |
| 118 | + state.from = vp.from; | |
| 119 | + } | |
| 120 | + if (vp.to > state.to) { | |
| 121 | + updateFoldInfo(cm, state.to, vp.to); | |
| 122 | + state.to = vp.to; | |
| 123 | + } | |
| 124 | + }); | |
| 125 | + } | |
| 126 | + }, opts.updateViewportTimeSpan || 400); | |
| 127 | + } | |
| 128 | + | |
| 129 | + function onFold(cm, from) { | |
| 130 | + var state = cm.state.foldGutter, line = from.line; | |
| 131 | + if (line >= state.from && line < state.to) | |
| 132 | + updateFoldInfo(cm, line, line + 1); | |
| 133 | + } | |
| 134 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,44 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | +"use strict"; | |
| 13 | + | |
| 14 | +CodeMirror.registerHelper("fold", "indent", function(cm, start) { | |
| 15 | + var tabSize = cm.getOption("tabSize"), firstLine = cm.getLine(start.line); | |
| 16 | + if (!/\S/.test(firstLine)) return; | |
| 17 | + var getIndent = function(line) { | |
| 18 | + return CodeMirror.countColumn(line, null, tabSize); | |
| 19 | + }; | |
| 20 | + var myIndent = getIndent(firstLine); | |
| 21 | + var lastLineInFold = null; | |
| 22 | + // Go through lines until we find a line that definitely doesn't belong in | |
| 23 | + // the block we're folding, or to the end. | |
| 24 | + for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) { | |
| 25 | + var curLine = cm.getLine(i); | |
| 26 | + var curIndent = getIndent(curLine); | |
| 27 | + if (curIndent > myIndent) { | |
| 28 | + // Lines with a greater indent are considered part of the block. | |
| 29 | + lastLineInFold = i; | |
| 30 | + } else if (!/\S/.test(curLine)) { | |
| 31 | + // Empty lines might be breaks within the block we're trying to fold. | |
| 32 | + } else { | |
| 33 | + // A non-empty line at an indent equal to or less than ours marks the | |
| 34 | + // start of another block. | |
| 35 | + break; | |
| 36 | + } | |
| 37 | + } | |
| 38 | + if (lastLineInFold) return { | |
| 39 | + from: CodeMirror.Pos(start.line, firstLine.length), | |
| 40 | + to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length) | |
| 41 | + }; | |
| 42 | +}); | |
| 43 | + | |
| 44 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,49 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | +"use strict"; | |
| 13 | + | |
| 14 | +CodeMirror.registerHelper("fold", "markdown", function(cm, start) { | |
| 15 | + var maxDepth = 100; | |
| 16 | + | |
| 17 | + function isHeader(lineNo) { | |
| 18 | + var tokentype = cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0)); | |
| 19 | + return tokentype && /\bheader\b/.test(tokentype); | |
| 20 | + } | |
| 21 | + | |
| 22 | + function headerLevel(lineNo, line, nextLine) { | |
| 23 | + var match = line && line.match(/^#+/); | |
| 24 | + if (match && isHeader(lineNo)) return match[0].length; | |
| 25 | + match = nextLine && nextLine.match(/^[=\-]+\s*$/); | |
| 26 | + if (match && isHeader(lineNo + 1)) return nextLine[0] == "=" ? 1 : 2; | |
| 27 | + return maxDepth; | |
| 28 | + } | |
| 29 | + | |
| 30 | + var firstLine = cm.getLine(start.line), nextLine = cm.getLine(start.line + 1); | |
| 31 | + var level = headerLevel(start.line, firstLine, nextLine); | |
| 32 | + if (level === maxDepth) return undefined; | |
| 33 | + | |
| 34 | + var lastLineNo = cm.lastLine(); | |
| 35 | + var end = start.line, nextNextLine = cm.getLine(end + 2); | |
| 36 | + while (end < lastLineNo) { | |
| 37 | + if (headerLevel(end + 1, nextLine, nextNextLine) <= level) break; | |
| 38 | + ++end; | |
| 39 | + nextLine = nextNextLine; | |
| 40 | + nextNextLine = cm.getLine(end + 2); | |
| 41 | + } | |
| 42 | + | |
| 43 | + return { | |
| 44 | + from: CodeMirror.Pos(start.line, firstLine.length), | |
| 45 | + to: CodeMirror.Pos(end, cm.getLine(end).length) | |
| 46 | + }; | |
| 47 | +}); | |
| 48 | + | |
| 49 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,182 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + "use strict"; | |
| 13 | + | |
| 14 | + var Pos = CodeMirror.Pos; | |
| 15 | + function cmp(a, b) { return a.line - b.line || a.ch - b.ch; } | |
| 16 | + | |
| 17 | + var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD"; | |
| 18 | + var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; | |
| 19 | + var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g"); | |
| 20 | + | |
| 21 | + function Iter(cm, line, ch, range) { | |
| 22 | + this.line = line; this.ch = ch; | |
| 23 | + this.cm = cm; this.text = cm.getLine(line); | |
| 24 | + this.min = range ? range.from : cm.firstLine(); | |
| 25 | + this.max = range ? range.to - 1 : cm.lastLine(); | |
| 26 | + } | |
| 27 | + | |
| 28 | + function tagAt(iter, ch) { | |
| 29 | + var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch)); | |
| 30 | + return type && /\btag\b/.test(type); | |
| 31 | + } | |
| 32 | + | |
| 33 | + function nextLine(iter) { | |
| 34 | + if (iter.line >= iter.max) return; | |
| 35 | + iter.ch = 0; | |
| 36 | + iter.text = iter.cm.getLine(++iter.line); | |
| 37 | + return true; | |
| 38 | + } | |
| 39 | + function prevLine(iter) { | |
| 40 | + if (iter.line <= iter.min) return; | |
| 41 | + iter.text = iter.cm.getLine(--iter.line); | |
| 42 | + iter.ch = iter.text.length; | |
| 43 | + return true; | |
| 44 | + } | |
| 45 | + | |
| 46 | + function toTagEnd(iter) { | |
| 47 | + for (;;) { | |
| 48 | + var gt = iter.text.indexOf(">", iter.ch); | |
| 49 | + if (gt == -1) { if (nextLine(iter)) continue; else return; } | |
| 50 | + if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; } | |
| 51 | + var lastSlash = iter.text.lastIndexOf("/", gt); | |
| 52 | + var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt)); | |
| 53 | + iter.ch = gt + 1; | |
| 54 | + return selfClose ? "selfClose" : "regular"; | |
| 55 | + } | |
| 56 | + } | |
| 57 | + function toTagStart(iter) { | |
| 58 | + for (;;) { | |
| 59 | + var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1; | |
| 60 | + if (lt == -1) { if (prevLine(iter)) continue; else return; } | |
| 61 | + if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; } | |
| 62 | + xmlTagStart.lastIndex = lt; | |
| 63 | + iter.ch = lt; | |
| 64 | + var match = xmlTagStart.exec(iter.text); | |
| 65 | + if (match && match.index == lt) return match; | |
| 66 | + } | |
| 67 | + } | |
| 68 | + | |
| 69 | + function toNextTag(iter) { | |
| 70 | + for (;;) { | |
| 71 | + xmlTagStart.lastIndex = iter.ch; | |
| 72 | + var found = xmlTagStart.exec(iter.text); | |
| 73 | + if (!found) { if (nextLine(iter)) continue; else return; } | |
| 74 | + if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; } | |
| 75 | + iter.ch = found.index + found[0].length; | |
| 76 | + return found; | |
| 77 | + } | |
| 78 | + } | |
| 79 | + function toPrevTag(iter) { | |
| 80 | + for (;;) { | |
| 81 | + var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1; | |
| 82 | + if (gt == -1) { if (prevLine(iter)) continue; else return; } | |
| 83 | + if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; } | |
| 84 | + var lastSlash = iter.text.lastIndexOf("/", gt); | |
| 85 | + var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt)); | |
| 86 | + iter.ch = gt + 1; | |
| 87 | + return selfClose ? "selfClose" : "regular"; | |
| 88 | + } | |
| 89 | + } | |
| 90 | + | |
| 91 | + function findMatchingClose(iter, tag) { | |
| 92 | + var stack = []; | |
| 93 | + for (;;) { | |
| 94 | + var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0); | |
| 95 | + if (!next || !(end = toTagEnd(iter))) return; | |
| 96 | + if (end == "selfClose") continue; | |
| 97 | + if (next[1]) { // closing tag | |
| 98 | + for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) { | |
| 99 | + stack.length = i; | |
| 100 | + break; | |
| 101 | + } | |
| 102 | + if (i < 0 && (!tag || tag == next[2])) return { | |
| 103 | + tag: next[2], | |
| 104 | + from: Pos(startLine, startCh), | |
| 105 | + to: Pos(iter.line, iter.ch) | |
| 106 | + }; | |
| 107 | + } else { // opening tag | |
| 108 | + stack.push(next[2]); | |
| 109 | + } | |
| 110 | + } | |
| 111 | + } | |
| 112 | + function findMatchingOpen(iter, tag) { | |
| 113 | + var stack = []; | |
| 114 | + for (;;) { | |
| 115 | + var prev = toPrevTag(iter); | |
| 116 | + if (!prev) return; | |
| 117 | + if (prev == "selfClose") { toTagStart(iter); continue; } | |
| 118 | + var endLine = iter.line, endCh = iter.ch; | |
| 119 | + var start = toTagStart(iter); | |
| 120 | + if (!start) return; | |
| 121 | + if (start[1]) { // closing tag | |
| 122 | + stack.push(start[2]); | |
| 123 | + } else { // opening tag | |
| 124 | + for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) { | |
| 125 | + stack.length = i; | |
| 126 | + break; | |
| 127 | + } | |
| 128 | + if (i < 0 && (!tag || tag == start[2])) return { | |
| 129 | + tag: start[2], | |
| 130 | + from: Pos(iter.line, iter.ch), | |
| 131 | + to: Pos(endLine, endCh) | |
| 132 | + }; | |
| 133 | + } | |
| 134 | + } | |
| 135 | + } | |
| 136 | + | |
| 137 | + CodeMirror.registerHelper("fold", "xml", function(cm, start) { | |
| 138 | + var iter = new Iter(cm, start.line, 0); | |
| 139 | + for (;;) { | |
| 140 | + var openTag = toNextTag(iter), end; | |
| 141 | + if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return; | |
| 142 | + if (!openTag[1] && end != "selfClose") { | |
| 143 | + var start = Pos(iter.line, iter.ch); | |
| 144 | + var close = findMatchingClose(iter, openTag[2]); | |
| 145 | + return close && {from: start, to: close.from}; | |
| 146 | + } | |
| 147 | + } | |
| 148 | + }); | |
| 149 | + CodeMirror.findMatchingTag = function(cm, pos, range) { | |
| 150 | + var iter = new Iter(cm, pos.line, pos.ch, range); | |
| 151 | + if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return; | |
| 152 | + var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch); | |
| 153 | + var start = end && toTagStart(iter); | |
| 154 | + if (!end || !start || cmp(iter, pos) > 0) return; | |
| 155 | + var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]}; | |
| 156 | + if (end == "selfClose") return {open: here, close: null, at: "open"}; | |
| 157 | + | |
| 158 | + if (start[1]) { // closing tag | |
| 159 | + return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"}; | |
| 160 | + } else { // opening tag | |
| 161 | + iter = new Iter(cm, to.line, to.ch, range); | |
| 162 | + return {open: here, close: findMatchingClose(iter, start[2]), at: "open"}; | |
| 163 | + } | |
| 164 | + }; | |
| 165 | + | |
| 166 | + CodeMirror.findEnclosingTag = function(cm, pos, range) { | |
| 167 | + var iter = new Iter(cm, pos.line, pos.ch, range); | |
| 168 | + for (;;) { | |
| 169 | + var open = findMatchingOpen(iter); | |
| 170 | + if (!open) break; | |
| 171 | + var forward = new Iter(cm, pos.line, pos.ch, range); | |
| 172 | + var close = findMatchingClose(forward, open.tag); | |
| 173 | + if (close) return {open: open, close: close}; | |
| 174 | + } | |
| 175 | + }; | |
| 176 | + | |
| 177 | + // Used by addon/edit/closetag.js | |
| 178 | + CodeMirror.scanForClosingTag = function(cm, pos, name, end) { | |
| 179 | + var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null); | |
| 180 | + return findMatchingClose(iter, name); | |
| 181 | + }; | |
| 182 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,42 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + "use strict"; | |
| 13 | + | |
| 14 | + var WORD = /[\w$]+/, RANGE = 500; | |
| 15 | + | |
| 16 | + CodeMirror.registerHelper("hint", "anyword", function(editor, options) { | |
| 17 | + var word = options && options.word || WORD; | |
| 18 | + var range = options && options.range || RANGE; | |
| 19 | + var cur = editor.getCursor(), curLine = editor.getLine(cur.line); | |
| 20 | + var start = cur.ch, end = start; | |
| 21 | + while (end < curLine.length && word.test(curLine.charAt(end))) ++end; | |
| 22 | + while (start && word.test(curLine.charAt(start - 1))) --start; | |
| 23 | + var curWord = start != end && curLine.slice(start, end); | |
| 24 | + | |
| 25 | + var list = [], seen = {}; | |
| 26 | + var re = new RegExp(word.source, "g"); | |
| 27 | + for (var dir = -1; dir <= 1; dir += 2) { | |
| 28 | + var line = cur.line, endLine = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir; | |
| 29 | + for (; line != endLine; line += dir) { | |
| 30 | + var text = editor.getLine(line), m; | |
| 31 | + while (m = re.exec(text)) { | |
| 32 | + if (line == cur.line && m[0] === curWord) continue; | |
| 33 | + if ((!curWord || m[0].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, m[0])) { | |
| 34 | + seen[m[0]] = true; | |
| 35 | + list.push(m[0]); | |
| 36 | + } | |
| 37 | + } | |
| 38 | + } | |
| 39 | + } | |
| 40 | + return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)}; | |
| 41 | + }); | |
| 42 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,56 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror"), require("../../mode/css/css")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror", "../../mode/css/css"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + "use strict"; | |
| 13 | + | |
| 14 | + var pseudoClasses = {link: 1, visited: 1, active: 1, hover: 1, focus: 1, | |
| 15 | + "first-letter": 1, "first-line": 1, "first-child": 1, | |
| 16 | + before: 1, after: 1, lang: 1}; | |
| 17 | + | |
| 18 | + CodeMirror.registerHelper("hint", "css", function(cm) { | |
| 19 | + var cur = cm.getCursor(), token = cm.getTokenAt(cur); | |
| 20 | + var inner = CodeMirror.innerMode(cm.getMode(), token.state); | |
| 21 | + if (inner.mode.name != "css") return; | |
| 22 | + | |
| 23 | + var word = token.string, start = token.start, end = token.end; | |
| 24 | + if (/[^\w$_-]/.test(word)) { | |
| 25 | + word = ""; start = end = cur.ch; | |
| 26 | + } | |
| 27 | + | |
| 28 | + var spec = CodeMirror.resolveMode("text/css"); | |
| 29 | + | |
| 30 | + var result = []; | |
| 31 | + function add(keywords) { | |
| 32 | + for (var name in keywords) | |
| 33 | + if (!word || name.lastIndexOf(word, 0) == 0) | |
| 34 | + result.push(name); | |
| 35 | + } | |
| 36 | + | |
| 37 | + var st = inner.state.state; | |
| 38 | + if (st == "pseudo" || token.type == "variable-3") { | |
| 39 | + add(pseudoClasses); | |
| 40 | + } else if (st == "block" || st == "maybeprop") { | |
| 41 | + add(spec.propertyKeywords); | |
| 42 | + } else if (st == "prop" || st == "parens" || st == "at" || st == "params") { | |
| 43 | + add(spec.valueKeywords); | |
| 44 | + add(spec.colorKeywords); | |
| 45 | + } else if (st == "media" || st == "media_parens") { | |
| 46 | + add(spec.mediaTypes); | |
| 47 | + add(spec.mediaFeatures); | |
| 48 | + } | |
| 49 | + | |
| 50 | + if (result.length) return { | |
| 51 | + list: result, | |
| 52 | + from: CodeMirror.Pos(cur.line, start), | |
| 53 | + to: CodeMirror.Pos(cur.line, end) | |
| 54 | + }; | |
| 55 | + }); | |
| 56 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,348 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror", "./xml-hint")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror", "./xml-hint"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + "use strict"; | |
| 13 | + | |
| 14 | + var langs = "ab aa af ak sq am ar an hy as av ae ay az bm ba eu be bn bh bi bs br bg my ca ch ce ny zh cv kw co cr hr cs da dv nl dz en eo et ee fo fj fi fr ff gl ka de el gn gu ht ha he hz hi ho hu ia id ie ga ig ik io is it iu ja jv kl kn kr ks kk km ki rw ky kv kg ko ku kj la lb lg li ln lo lt lu lv gv mk mg ms ml mt mi mr mh mn na nv nb nd ne ng nn no ii nr oc oj cu om or os pa pi fa pl ps pt qu rm rn ro ru sa sc sd se sm sg sr gd sn si sk sl so st es su sw ss sv ta te tg th ti bo tk tl tn to tr ts tt tw ty ug uk ur uz ve vi vo wa cy wo fy xh yi yo za zu".split(" "); | |
| 15 | + var targets = ["_blank", "_self", "_top", "_parent"]; | |
| 16 | + var charsets = ["ascii", "utf-8", "utf-16", "latin1", "latin1"]; | |
| 17 | + var methods = ["get", "post", "put", "delete"]; | |
| 18 | + var encs = ["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"]; | |
| 19 | + var media = ["all", "screen", "print", "embossed", "braille", "handheld", "print", "projection", "screen", "tty", "tv", "speech", | |
| 20 | + "3d-glasses", "resolution [>][<][=] [X]", "device-aspect-ratio: X/Y", "orientation:portrait", | |
| 21 | + "orientation:landscape", "device-height: [X]", "device-width: [X]"]; | |
| 22 | + var s = { attrs: {} }; // Simple tag, reused for a whole lot of tags | |
| 23 | + | |
| 24 | + var data = { | |
| 25 | + a: { | |
| 26 | + attrs: { | |
| 27 | + href: null, ping: null, type: null, | |
| 28 | + media: media, | |
| 29 | + target: targets, | |
| 30 | + hreflang: langs | |
| 31 | + } | |
| 32 | + }, | |
| 33 | + abbr: s, | |
| 34 | + acronym: s, | |
| 35 | + address: s, | |
| 36 | + applet: s, | |
| 37 | + area: { | |
| 38 | + attrs: { | |
| 39 | + alt: null, coords: null, href: null, target: null, ping: null, | |
| 40 | + media: media, hreflang: langs, type: null, | |
| 41 | + shape: ["default", "rect", "circle", "poly"] | |
| 42 | + } | |
| 43 | + }, | |
| 44 | + article: s, | |
| 45 | + aside: s, | |
| 46 | + audio: { | |
| 47 | + attrs: { | |
| 48 | + src: null, mediagroup: null, | |
| 49 | + crossorigin: ["anonymous", "use-credentials"], | |
| 50 | + preload: ["none", "metadata", "auto"], | |
| 51 | + autoplay: ["", "autoplay"], | |
| 52 | + loop: ["", "loop"], | |
| 53 | + controls: ["", "controls"] | |
| 54 | + } | |
| 55 | + }, | |
| 56 | + b: s, | |
| 57 | + base: { attrs: { href: null, target: targets } }, | |
| 58 | + basefont: s, | |
| 59 | + bdi: s, | |
| 60 | + bdo: s, | |
| 61 | + big: s, | |
| 62 | + blockquote: { attrs: { cite: null } }, | |
| 63 | + body: s, | |
| 64 | + br: s, | |
| 65 | + button: { | |
| 66 | + attrs: { | |
| 67 | + form: null, formaction: null, name: null, value: null, | |
| 68 | + autofocus: ["", "autofocus"], | |
| 69 | + disabled: ["", "autofocus"], | |
| 70 | + formenctype: encs, | |
| 71 | + formmethod: methods, | |
| 72 | + formnovalidate: ["", "novalidate"], | |
| 73 | + formtarget: targets, | |
| 74 | + type: ["submit", "reset", "button"] | |
| 75 | + } | |
| 76 | + }, | |
| 77 | + canvas: { attrs: { width: null, height: null } }, | |
| 78 | + caption: s, | |
| 79 | + center: s, | |
| 80 | + cite: s, | |
| 81 | + code: s, | |
| 82 | + col: { attrs: { span: null } }, | |
| 83 | + colgroup: { attrs: { span: null } }, | |
| 84 | + command: { | |
| 85 | + attrs: { | |
| 86 | + type: ["command", "checkbox", "radio"], | |
| 87 | + label: null, icon: null, radiogroup: null, command: null, title: null, | |
| 88 | + disabled: ["", "disabled"], | |
| 89 | + checked: ["", "checked"] | |
| 90 | + } | |
| 91 | + }, | |
| 92 | + data: { attrs: { value: null } }, | |
| 93 | + datagrid: { attrs: { disabled: ["", "disabled"], multiple: ["", "multiple"] } }, | |
| 94 | + datalist: { attrs: { data: null } }, | |
| 95 | + dd: s, | |
| 96 | + del: { attrs: { cite: null, datetime: null } }, | |
| 97 | + details: { attrs: { open: ["", "open"] } }, | |
| 98 | + dfn: s, | |
| 99 | + dir: s, | |
| 100 | + div: s, | |
| 101 | + dl: s, | |
| 102 | + dt: s, | |
| 103 | + em: s, | |
| 104 | + embed: { attrs: { src: null, type: null, width: null, height: null } }, | |
| 105 | + eventsource: { attrs: { src: null } }, | |
| 106 | + fieldset: { attrs: { disabled: ["", "disabled"], form: null, name: null } }, | |
| 107 | + figcaption: s, | |
| 108 | + figure: s, | |
| 109 | + font: s, | |
| 110 | + footer: s, | |
| 111 | + form: { | |
| 112 | + attrs: { | |
| 113 | + action: null, name: null, | |
| 114 | + "accept-charset": charsets, | |
| 115 | + autocomplete: ["on", "off"], | |
| 116 | + enctype: encs, | |
| 117 | + method: methods, | |
| 118 | + novalidate: ["", "novalidate"], | |
| 119 | + target: targets | |
| 120 | + } | |
| 121 | + }, | |
| 122 | + frame: s, | |
| 123 | + frameset: s, | |
| 124 | + h1: s, h2: s, h3: s, h4: s, h5: s, h6: s, | |
| 125 | + head: { | |
| 126 | + attrs: {}, | |
| 127 | + children: ["title", "base", "link", "style", "meta", "script", "noscript", "command"] | |
| 128 | + }, | |
| 129 | + header: s, | |
| 130 | + hgroup: s, | |
| 131 | + hr: s, | |
| 132 | + html: { | |
| 133 | + attrs: { manifest: null }, | |
| 134 | + children: ["head", "body"] | |
| 135 | + }, | |
| 136 | + i: s, | |
| 137 | + iframe: { | |
| 138 | + attrs: { | |
| 139 | + src: null, srcdoc: null, name: null, width: null, height: null, | |
| 140 | + sandbox: ["allow-top-navigation", "allow-same-origin", "allow-forms", "allow-scripts"], | |
| 141 | + seamless: ["", "seamless"] | |
| 142 | + } | |
| 143 | + }, | |
| 144 | + img: { | |
| 145 | + attrs: { | |
| 146 | + alt: null, src: null, ismap: null, usemap: null, width: null, height: null, | |
| 147 | + crossorigin: ["anonymous", "use-credentials"] | |
| 148 | + } | |
| 149 | + }, | |
| 150 | + input: { | |
| 151 | + attrs: { | |
| 152 | + alt: null, dirname: null, form: null, formaction: null, | |
| 153 | + height: null, list: null, max: null, maxlength: null, min: null, | |
| 154 | + name: null, pattern: null, placeholder: null, size: null, src: null, | |
| 155 | + step: null, value: null, width: null, | |
| 156 | + accept: ["audio/*", "video/*", "image/*"], | |
| 157 | + autocomplete: ["on", "off"], | |
| 158 | + autofocus: ["", "autofocus"], | |
| 159 | + checked: ["", "checked"], | |
| 160 | + disabled: ["", "disabled"], | |
| 161 | + formenctype: encs, | |
| 162 | + formmethod: methods, | |
| 163 | + formnovalidate: ["", "novalidate"], | |
| 164 | + formtarget: targets, | |
| 165 | + multiple: ["", "multiple"], | |
| 166 | + readonly: ["", "readonly"], | |
| 167 | + required: ["", "required"], | |
| 168 | + type: ["hidden", "text", "search", "tel", "url", "email", "password", "datetime", "date", "month", | |
| 169 | + "week", "time", "datetime-local", "number", "range", "color", "checkbox", "radio", | |
| 170 | + "file", "submit", "image", "reset", "button"] | |
| 171 | + } | |
| 172 | + }, | |
| 173 | + ins: { attrs: { cite: null, datetime: null } }, | |
| 174 | + kbd: s, | |
| 175 | + keygen: { | |
| 176 | + attrs: { | |
| 177 | + challenge: null, form: null, name: null, | |
| 178 | + autofocus: ["", "autofocus"], | |
| 179 | + disabled: ["", "disabled"], | |
| 180 | + keytype: ["RSA"] | |
| 181 | + } | |
| 182 | + }, | |
| 183 | + label: { attrs: { "for": null, form: null } }, | |
| 184 | + legend: s, | |
| 185 | + li: { attrs: { value: null } }, | |
| 186 | + link: { | |
| 187 | + attrs: { | |
| 188 | + href: null, type: null, | |
| 189 | + hreflang: langs, | |
| 190 | + media: media, | |
| 191 | + sizes: ["all", "16x16", "16x16 32x32", "16x16 32x32 64x64"] | |
| 192 | + } | |
| 193 | + }, | |
| 194 | + map: { attrs: { name: null } }, | |
| 195 | + mark: s, | |
| 196 | + menu: { attrs: { label: null, type: ["list", "context", "toolbar"] } }, | |
| 197 | + meta: { | |
| 198 | + attrs: { | |
| 199 | + content: null, | |
| 200 | + charset: charsets, | |
| 201 | + name: ["viewport", "application-name", "author", "description", "generator", "keywords"], | |
| 202 | + "http-equiv": ["content-language", "content-type", "default-style", "refresh"] | |
| 203 | + } | |
| 204 | + }, | |
| 205 | + meter: { attrs: { value: null, min: null, low: null, high: null, max: null, optimum: null } }, | |
| 206 | + nav: s, | |
| 207 | + noframes: s, | |
| 208 | + noscript: s, | |
| 209 | + object: { | |
| 210 | + attrs: { | |
| 211 | + data: null, type: null, name: null, usemap: null, form: null, width: null, height: null, | |
| 212 | + typemustmatch: ["", "typemustmatch"] | |
| 213 | + } | |
| 214 | + }, | |
| 215 | + ol: { attrs: { reversed: ["", "reversed"], start: null, type: ["1", "a", "A", "i", "I"] } }, | |
| 216 | + optgroup: { attrs: { disabled: ["", "disabled"], label: null } }, | |
| 217 | + option: { attrs: { disabled: ["", "disabled"], label: null, selected: ["", "selected"], value: null } }, | |
| 218 | + output: { attrs: { "for": null, form: null, name: null } }, | |
| 219 | + p: s, | |
| 220 | + param: { attrs: { name: null, value: null } }, | |
| 221 | + pre: s, | |
| 222 | + progress: { attrs: { value: null, max: null } }, | |
| 223 | + q: { attrs: { cite: null } }, | |
| 224 | + rp: s, | |
| 225 | + rt: s, | |
| 226 | + ruby: s, | |
| 227 | + s: s, | |
| 228 | + samp: s, | |
| 229 | + script: { | |
| 230 | + attrs: { | |
| 231 | + type: ["text/javascript"], | |
| 232 | + src: null, | |
| 233 | + async: ["", "async"], | |
| 234 | + defer: ["", "defer"], | |
| 235 | + charset: charsets | |
| 236 | + } | |
| 237 | + }, | |
| 238 | + section: s, | |
| 239 | + select: { | |
| 240 | + attrs: { | |
| 241 | + form: null, name: null, size: null, | |
| 242 | + autofocus: ["", "autofocus"], | |
| 243 | + disabled: ["", "disabled"], | |
| 244 | + multiple: ["", "multiple"] | |
| 245 | + } | |
| 246 | + }, | |
| 247 | + small: s, | |
| 248 | + source: { attrs: { src: null, type: null, media: null } }, | |
| 249 | + span: s, | |
| 250 | + strike: s, | |
| 251 | + strong: s, | |
| 252 | + style: { | |
| 253 | + attrs: { | |
| 254 | + type: ["text/css"], | |
| 255 | + media: media, | |
| 256 | + scoped: null | |
| 257 | + } | |
| 258 | + }, | |
| 259 | + sub: s, | |
| 260 | + summary: s, | |
| 261 | + sup: s, | |
| 262 | + table: s, | |
| 263 | + tbody: s, | |
| 264 | + td: { attrs: { colspan: null, rowspan: null, headers: null } }, | |
| 265 | + textarea: { | |
| 266 | + attrs: { | |
| 267 | + dirname: null, form: null, maxlength: null, name: null, placeholder: null, | |
| 268 | + rows: null, cols: null, | |
| 269 | + autofocus: ["", "autofocus"], | |
| 270 | + disabled: ["", "disabled"], | |
| 271 | + readonly: ["", "readonly"], | |
| 272 | + required: ["", "required"], | |
| 273 | + wrap: ["soft", "hard"] | |
| 274 | + } | |
| 275 | + }, | |
| 276 | + tfoot: s, | |
| 277 | + th: { attrs: { colspan: null, rowspan: null, headers: null, scope: ["row", "col", "rowgroup", "colgroup"] } }, | |
| 278 | + thead: s, | |
| 279 | + time: { attrs: { datetime: null } }, | |
| 280 | + title: s, | |
| 281 | + tr: s, | |
| 282 | + track: { | |
| 283 | + attrs: { | |
| 284 | + src: null, label: null, "default": null, | |
| 285 | + kind: ["subtitles", "captions", "descriptions", "chapters", "metadata"], | |
| 286 | + srclang: langs | |
| 287 | + } | |
| 288 | + }, | |
| 289 | + tt: s, | |
| 290 | + u: s, | |
| 291 | + ul: s, | |
| 292 | + "var": s, | |
| 293 | + video: { | |
| 294 | + attrs: { | |
| 295 | + src: null, poster: null, width: null, height: null, | |
| 296 | + crossorigin: ["anonymous", "use-credentials"], | |
| 297 | + preload: ["auto", "metadata", "none"], | |
| 298 | + autoplay: ["", "autoplay"], | |
| 299 | + mediagroup: ["movie"], | |
| 300 | + muted: ["", "muted"], | |
| 301 | + controls: ["", "controls"] | |
| 302 | + } | |
| 303 | + }, | |
| 304 | + wbr: s | |
| 305 | + }; | |
| 306 | + | |
| 307 | + var globalAttrs = { | |
| 308 | + accesskey: ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], | |
| 309 | + "class": null, | |
| 310 | + contenteditable: ["true", "false"], | |
| 311 | + contextmenu: null, | |
| 312 | + dir: ["ltr", "rtl", "auto"], | |
| 313 | + draggable: ["true", "false", "auto"], | |
| 314 | + dropzone: ["copy", "move", "link", "string:", "file:"], | |
| 315 | + hidden: ["hidden"], | |
| 316 | + id: null, | |
| 317 | + inert: ["inert"], | |
| 318 | + itemid: null, | |
| 319 | + itemprop: null, | |
| 320 | + itemref: null, | |
| 321 | + itemscope: ["itemscope"], | |
| 322 | + itemtype: null, | |
| 323 | + lang: ["en", "es"], | |
| 324 | + spellcheck: ["true", "false"], | |
| 325 | + style: null, | |
| 326 | + tabindex: ["1", "2", "3", "4", "5", "6", "7", "8", "9"], | |
| 327 | + title: null, | |
| 328 | + translate: ["yes", "no"], | |
| 329 | + onclick: null, | |
| 330 | + rel: ["stylesheet", "alternate", "author", "bookmark", "help", "license", "next", "nofollow", "noreferrer", "prefetch", "prev", "search", "tag"] | |
| 331 | + }; | |
| 332 | + function populate(obj) { | |
| 333 | + for (var attr in globalAttrs) if (globalAttrs.hasOwnProperty(attr)) | |
| 334 | + obj.attrs[attr] = globalAttrs[attr]; | |
| 335 | + } | |
| 336 | + | |
| 337 | + populate(s); | |
| 338 | + for (var tag in data) if (data.hasOwnProperty(tag) && data[tag] != s) | |
| 339 | + populate(data[tag]); | |
| 340 | + | |
| 341 | + CodeMirror.htmlSchema = data; | |
| 342 | + function htmlHint(cm, options) { | |
| 343 | + var local = {schemaInfo: data}; | |
| 344 | + if (options) for (var opt in options) local[opt] = options[opt]; | |
| 345 | + return CodeMirror.hint.xml(cm, local); | |
| 346 | + } | |
| 347 | + CodeMirror.registerHelper("hint", "html", htmlHint); | |
| 348 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,141 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + var Pos = CodeMirror.Pos; | |
| 13 | + | |
| 14 | + function forEach(arr, f) { | |
| 15 | + for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); | |
| 16 | + } | |
| 17 | + | |
| 18 | + function arrayContains(arr, item) { | |
| 19 | + if (!Array.prototype.indexOf) { | |
| 20 | + var i = arr.length; | |
| 21 | + while (i--) { | |
| 22 | + if (arr[i] === item) { | |
| 23 | + return true; | |
| 24 | + } | |
| 25 | + } | |
| 26 | + return false; | |
| 27 | + } | |
| 28 | + return arr.indexOf(item) != -1; | |
| 29 | + } | |
| 30 | + | |
| 31 | + function scriptHint(editor, keywords, getToken, options) { | |
| 32 | + // Find the token at the cursor | |
| 33 | + var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token; | |
| 34 | + if (/\b(?:string|comment)\b/.test(token.type)) return; | |
| 35 | + token.state = CodeMirror.innerMode(editor.getMode(), token.state).state; | |
| 36 | + | |
| 37 | + // If it's not a 'word-style' token, ignore the token. | |
| 38 | + if (!/^[\w$_]*$/.test(token.string)) { | |
| 39 | + token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state, | |
| 40 | + type: token.string == "." ? "property" : null}; | |
| 41 | + } | |
| 42 | + // If it is a property, find out what it is a property of. | |
| 43 | + while (tprop.type == "property") { | |
| 44 | + tprop = getToken(editor, Pos(cur.line, tprop.start)); | |
| 45 | + if (tprop.string != ".") return; | |
| 46 | + tprop = getToken(editor, Pos(cur.line, tprop.start)); | |
| 47 | + if (!context) var context = []; | |
| 48 | + context.push(tprop); | |
| 49 | + } | |
| 50 | + return {list: getCompletions(token, context, keywords, options), | |
| 51 | + from: Pos(cur.line, token.start), | |
| 52 | + to: Pos(cur.line, token.end)}; | |
| 53 | + } | |
| 54 | + | |
| 55 | + function javascriptHint(editor, options) { | |
| 56 | + return scriptHint(editor, javascriptKeywords, | |
| 57 | + function (e, cur) {return e.getTokenAt(cur);}, | |
| 58 | + options); | |
| 59 | + }; | |
| 60 | + CodeMirror.registerHelper("hint", "javascript", javascriptHint); | |
| 61 | + | |
| 62 | + function getCoffeeScriptToken(editor, cur) { | |
| 63 | + // This getToken, it is for coffeescript, imitates the behavior of | |
| 64 | + // getTokenAt method in javascript.js, that is, returning "property" | |
| 65 | + // type and treat "." as indepenent token. | |
| 66 | + var token = editor.getTokenAt(cur); | |
| 67 | + if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') { | |
| 68 | + token.end = token.start; | |
| 69 | + token.string = '.'; | |
| 70 | + token.type = "property"; | |
| 71 | + } | |
| 72 | + else if (/^\.[\w$_]*$/.test(token.string)) { | |
| 73 | + token.type = "property"; | |
| 74 | + token.start++; | |
| 75 | + token.string = token.string.replace(/\./, ''); | |
| 76 | + } | |
| 77 | + return token; | |
| 78 | + } | |
| 79 | + | |
| 80 | + function coffeescriptHint(editor, options) { | |
| 81 | + return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options); | |
| 82 | + } | |
| 83 | + CodeMirror.registerHelper("hint", "coffeescript", coffeescriptHint); | |
| 84 | + | |
| 85 | + var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " + | |
| 86 | + "toUpperCase toLowerCase split concat match replace search").split(" "); | |
| 87 | + var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " + | |
| 88 | + "lastIndexOf every some filter forEach map reduce reduceRight ").split(" "); | |
| 89 | + var funcProps = "prototype apply call bind".split(" "); | |
| 90 | + var javascriptKeywords = ("break case catch continue debugger default delete do else false finally for function " + | |
| 91 | + "if in instanceof new null return switch throw true try typeof var void while with").split(" "); | |
| 92 | + var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " + | |
| 93 | + "if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" "); | |
| 94 | + | |
| 95 | + function getCompletions(token, context, keywords, options) { | |
| 96 | + var found = [], start = token.string; | |
| 97 | + function maybeAdd(str) { | |
| 98 | + if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str); | |
| 99 | + } | |
| 100 | + function gatherCompletions(obj) { | |
| 101 | + if (typeof obj == "string") forEach(stringProps, maybeAdd); | |
| 102 | + else if (obj instanceof Array) forEach(arrayProps, maybeAdd); | |
| 103 | + else if (obj instanceof Function) forEach(funcProps, maybeAdd); | |
| 104 | + for (var name in obj) maybeAdd(name); | |
| 105 | + } | |
| 106 | + | |
| 107 | + if (context && context.length) { | |
| 108 | + // If this is a property, see if it belongs to some object we can | |
| 109 | + // find in the current environment. | |
| 110 | + var obj = context.pop(), base; | |
| 111 | + if (obj.type && obj.type.indexOf("variable") === 0) { | |
| 112 | + if (options && options.additionalContext) | |
| 113 | + base = options.additionalContext[obj.string]; | |
| 114 | + if (!options || options.useGlobalScope !== false) | |
| 115 | + base = base || window[obj.string]; | |
| 116 | + } else if (obj.type == "string") { | |
| 117 | + base = ""; | |
| 118 | + } else if (obj.type == "atom") { | |
| 119 | + base = 1; | |
| 120 | + } else if (obj.type == "function") { | |
| 121 | + if (window.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') && | |
| 122 | + (typeof window.jQuery == 'function')) | |
| 123 | + base = window.jQuery(); | |
| 124 | + else if (window._ != null && (obj.string == '_') && (typeof window._ == 'function')) | |
| 125 | + base = window._(); | |
| 126 | + } | |
| 127 | + while (base != null && context.length) | |
| 128 | + base = base[context.pop().string]; | |
| 129 | + if (base != null) gatherCompletions(base); | |
| 130 | + } else { | |
| 131 | + // If not, just look in the window object and any local scope | |
| 132 | + // (reading into JS mode internals to get at the local and global variables) | |
| 133 | + for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name); | |
| 134 | + for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name); | |
| 135 | + if (!options || options.useGlobalScope !== false) | |
| 136 | + gatherCompletions(window); | |
| 137 | + forEach(keywords, maybeAdd); | |
| 138 | + } | |
| 139 | + return found; | |
| 140 | + } | |
| 141 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,102 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + "use strict"; | |
| 13 | + | |
| 14 | + function forEach(arr, f) { | |
| 15 | + for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); | |
| 16 | + } | |
| 17 | + | |
| 18 | + function arrayContains(arr, item) { | |
| 19 | + if (!Array.prototype.indexOf) { | |
| 20 | + var i = arr.length; | |
| 21 | + while (i--) { | |
| 22 | + if (arr[i] === item) { | |
| 23 | + return true; | |
| 24 | + } | |
| 25 | + } | |
| 26 | + return false; | |
| 27 | + } | |
| 28 | + return arr.indexOf(item) != -1; | |
| 29 | + } | |
| 30 | + | |
| 31 | + function scriptHint(editor, _keywords, getToken) { | |
| 32 | + // Find the token at the cursor | |
| 33 | + var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token; | |
| 34 | + // If it's not a 'word-style' token, ignore the token. | |
| 35 | + | |
| 36 | + if (!/^[\w$_]*$/.test(token.string)) { | |
| 37 | + token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state, | |
| 38 | + className: token.string == ":" ? "python-type" : null}; | |
| 39 | + } | |
| 40 | + | |
| 41 | + if (!context) var context = []; | |
| 42 | + context.push(tprop); | |
| 43 | + | |
| 44 | + var completionList = getCompletions(token, context); | |
| 45 | + completionList = completionList.sort(); | |
| 46 | + | |
| 47 | + return {list: completionList, | |
| 48 | + from: CodeMirror.Pos(cur.line, token.start), | |
| 49 | + to: CodeMirror.Pos(cur.line, token.end)}; | |
| 50 | + } | |
| 51 | + | |
| 52 | + function pythonHint(editor) { | |
| 53 | + return scriptHint(editor, pythonKeywordsU, function (e, cur) {return e.getTokenAt(cur);}); | |
| 54 | + } | |
| 55 | + CodeMirror.registerHelper("hint", "python", pythonHint); | |
| 56 | + | |
| 57 | + var pythonKeywords = "and del from not while as elif global or with assert else if pass yield" | |
| 58 | ++ "break except import print class exec in raise continue finally is return def for lambda try"; | |
| 59 | + var pythonKeywordsL = pythonKeywords.split(" "); | |
| 60 | + var pythonKeywordsU = pythonKeywords.toUpperCase().split(" "); | |
| 61 | + | |
| 62 | + var pythonBuiltins = "abs divmod input open staticmethod all enumerate int ord str " | |
| 63 | ++ "any eval isinstance pow sum basestring execfile issubclass print super" | |
| 64 | ++ "bin file iter property tuple bool filter len range type" | |
| 65 | ++ "bytearray float list raw_input unichr callable format locals reduce unicode" | |
| 66 | ++ "chr frozenset long reload vars classmethod getattr map repr xrange" | |
| 67 | ++ "cmp globals max reversed zip compile hasattr memoryview round __import__" | |
| 68 | ++ "complex hash min set apply delattr help next setattr buffer" | |
| 69 | ++ "dict hex object slice coerce dir id oct sorted intern "; | |
| 70 | + var pythonBuiltinsL = pythonBuiltins.split(" ").join("() ").split(" "); | |
| 71 | + var pythonBuiltinsU = pythonBuiltins.toUpperCase().split(" ").join("() ").split(" "); | |
| 72 | + | |
| 73 | + function getCompletions(token, context) { | |
| 74 | + var found = [], start = token.string; | |
| 75 | + function maybeAdd(str) { | |
| 76 | + if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str); | |
| 77 | + } | |
| 78 | + | |
| 79 | + function gatherCompletions(_obj) { | |
| 80 | + forEach(pythonBuiltinsL, maybeAdd); | |
| 81 | + forEach(pythonBuiltinsU, maybeAdd); | |
| 82 | + forEach(pythonKeywordsL, maybeAdd); | |
| 83 | + forEach(pythonKeywordsU, maybeAdd); | |
| 84 | + } | |
| 85 | + | |
| 86 | + if (context) { | |
| 87 | + // If this is a property, see if it belongs to some object we can | |
| 88 | + // find in the current environment. | |
| 89 | + var obj = context.pop(), base; | |
| 90 | + | |
| 91 | + if (obj.type == "variable") | |
| 92 | + base = obj.string; | |
| 93 | + else if(obj.type == "variable-3") | |
| 94 | + base = ":" + obj.string; | |
| 95 | + | |
| 96 | + while (base != null && context.length) | |
| 97 | + base = base[context.pop().string]; | |
| 98 | + if (base != null) gatherCompletions(base); | |
| 99 | + } | |
| 100 | + return found; | |
| 101 | + } | |
| 102 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,38 @@ |
| 1 | +.CodeMirror-hints { | |
| 2 | + position: absolute; | |
| 3 | + z-index: 10; | |
| 4 | + overflow: hidden; | |
| 5 | + list-style: none; | |
| 6 | + | |
| 7 | + margin: 0; | |
| 8 | + padding: 2px; | |
| 9 | + | |
| 10 | + -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2); | |
| 11 | + -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); | |
| 12 | + box-shadow: 2px 3px 5px rgba(0,0,0,.2); | |
| 13 | + border-radius: 3px; | |
| 14 | + border: 1px solid silver; | |
| 15 | + | |
| 16 | + background: white; | |
| 17 | + font-size: 90%; | |
| 18 | + font-family: monospace; | |
| 19 | + | |
| 20 | + max-height: 20em; | |
| 21 | + overflow-y: auto; | |
| 22 | +} | |
| 23 | + | |
| 24 | +.CodeMirror-hint { | |
| 25 | + margin: 0; | |
| 26 | + padding: 0 4px; | |
| 27 | + border-radius: 2px; | |
| 28 | + max-width: 19em; | |
| 29 | + overflow: hidden; | |
| 30 | + white-space: pre; | |
| 31 | + color: black; | |
| 32 | + cursor: pointer; | |
| 33 | +} | |
| 34 | + | |
| 35 | +li.CodeMirror-hint-active { | |
| 36 | + background: #08f; | |
| 37 | + color: white; | |
| 38 | +} | ... | ... |
| ... | ... | @@ -0,0 +1,389 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + "use strict"; | |
| 13 | + | |
| 14 | + var HINT_ELEMENT_CLASS = "CodeMirror-hint"; | |
| 15 | + var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active"; | |
| 16 | + | |
| 17 | + // This is the old interface, kept around for now to stay | |
| 18 | + // backwards-compatible. | |
| 19 | + CodeMirror.showHint = function(cm, getHints, options) { | |
| 20 | + if (!getHints) return cm.showHint(options); | |
| 21 | + if (options && options.async) getHints.async = true; | |
| 22 | + var newOpts = {hint: getHints}; | |
| 23 | + if (options) for (var prop in options) newOpts[prop] = options[prop]; | |
| 24 | + return cm.showHint(newOpts); | |
| 25 | + }; | |
| 26 | + | |
| 27 | + CodeMirror.defineExtension("showHint", function(options) { | |
| 28 | + // We want a single cursor position. | |
| 29 | + if (this.listSelections().length > 1 || this.somethingSelected()) return; | |
| 30 | + | |
| 31 | + if (this.state.completionActive) this.state.completionActive.close(); | |
| 32 | + var completion = this.state.completionActive = new Completion(this, options); | |
| 33 | + var getHints = completion.options.hint; | |
| 34 | + if (!getHints) return; | |
| 35 | + | |
| 36 | + CodeMirror.signal(this, "startCompletion", this); | |
| 37 | + if (getHints.async) | |
| 38 | + getHints(this, function(hints) { completion.showHints(hints); }, completion.options); | |
| 39 | + else | |
| 40 | + return completion.showHints(getHints(this, completion.options)); | |
| 41 | + }); | |
| 42 | + | |
| 43 | + function Completion(cm, options) { | |
| 44 | + this.cm = cm; | |
| 45 | + this.options = this.buildOptions(options); | |
| 46 | + this.widget = this.onClose = null; | |
| 47 | + } | |
| 48 | + | |
| 49 | + Completion.prototype = { | |
| 50 | + close: function() { | |
| 51 | + if (!this.active()) return; | |
| 52 | + this.cm.state.completionActive = null; | |
| 53 | + | |
| 54 | + if (this.widget) this.widget.close(); | |
| 55 | + if (this.onClose) this.onClose(); | |
| 56 | + CodeMirror.signal(this.cm, "endCompletion", this.cm); | |
| 57 | + }, | |
| 58 | + | |
| 59 | + active: function() { | |
| 60 | + return this.cm.state.completionActive == this; | |
| 61 | + }, | |
| 62 | + | |
| 63 | + pick: function(data, i) { | |
| 64 | + var completion = data.list[i]; | |
| 65 | + if (completion.hint) completion.hint(this.cm, data, completion); | |
| 66 | + else this.cm.replaceRange(getText(completion), completion.from || data.from, | |
| 67 | + completion.to || data.to, "complete"); | |
| 68 | + CodeMirror.signal(data, "pick", completion); | |
| 69 | + this.close(); | |
| 70 | + }, | |
| 71 | + | |
| 72 | + showHints: function(data) { | |
| 73 | + if (!data || !data.list.length || !this.active()) return this.close(); | |
| 74 | + | |
| 75 | + if (this.options.completeSingle && data.list.length == 1) | |
| 76 | + this.pick(data, 0); | |
| 77 | + else | |
| 78 | + this.showWidget(data); | |
| 79 | + }, | |
| 80 | + | |
| 81 | + showWidget: function(data) { | |
| 82 | + this.widget = new Widget(this, data); | |
| 83 | + CodeMirror.signal(data, "shown"); | |
| 84 | + | |
| 85 | + var debounce = 0, completion = this, finished; | |
| 86 | + var closeOn = this.options.closeCharacters; | |
| 87 | + var startPos = this.cm.getCursor(), startLen = this.cm.getLine(startPos.line).length; | |
| 88 | + | |
| 89 | + var requestAnimationFrame = window.requestAnimationFrame || function(fn) { | |
| 90 | + return setTimeout(fn, 1000/60); | |
| 91 | + }; | |
| 92 | + var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout; | |
| 93 | + | |
| 94 | + function done() { | |
| 95 | + if (finished) return; | |
| 96 | + finished = true; | |
| 97 | + completion.close(); | |
| 98 | + completion.cm.off("cursorActivity", activity); | |
| 99 | + if (data) CodeMirror.signal(data, "close"); | |
| 100 | + } | |
| 101 | + | |
| 102 | + function update() { | |
| 103 | + if (finished) return; | |
| 104 | + CodeMirror.signal(data, "update"); | |
| 105 | + var getHints = completion.options.hint; | |
| 106 | + if (getHints.async) | |
| 107 | + getHints(completion.cm, finishUpdate, completion.options); | |
| 108 | + else | |
| 109 | + finishUpdate(getHints(completion.cm, completion.options)); | |
| 110 | + } | |
| 111 | + function finishUpdate(data_) { | |
| 112 | + data = data_; | |
| 113 | + if (finished) return; | |
| 114 | + if (!data || !data.list.length) return done(); | |
| 115 | + if (completion.widget) completion.widget.close(); | |
| 116 | + completion.widget = new Widget(completion, data); | |
| 117 | + } | |
| 118 | + | |
| 119 | + function clearDebounce() { | |
| 120 | + if (debounce) { | |
| 121 | + cancelAnimationFrame(debounce); | |
| 122 | + debounce = 0; | |
| 123 | + } | |
| 124 | + } | |
| 125 | + | |
| 126 | + function activity() { | |
| 127 | + clearDebounce(); | |
| 128 | + var pos = completion.cm.getCursor(), line = completion.cm.getLine(pos.line); | |
| 129 | + if (pos.line != startPos.line || line.length - pos.ch != startLen - startPos.ch || | |
| 130 | + pos.ch < startPos.ch || completion.cm.somethingSelected() || | |
| 131 | + (pos.ch && closeOn.test(line.charAt(pos.ch - 1)))) { | |
| 132 | + completion.close(); | |
| 133 | + } else { | |
| 134 | + debounce = requestAnimationFrame(update); | |
| 135 | + if (completion.widget) completion.widget.close(); | |
| 136 | + } | |
| 137 | + } | |
| 138 | + this.cm.on("cursorActivity", activity); | |
| 139 | + this.onClose = done; | |
| 140 | + }, | |
| 141 | + | |
| 142 | + buildOptions: function(options) { | |
| 143 | + var editor = this.cm.options.hintOptions; | |
| 144 | + var out = {}; | |
| 145 | + for (var prop in defaultOptions) out[prop] = defaultOptions[prop]; | |
| 146 | + if (editor) for (var prop in editor) | |
| 147 | + if (editor[prop] !== undefined) out[prop] = editor[prop]; | |
| 148 | + if (options) for (var prop in options) | |
| 149 | + if (options[prop] !== undefined) out[prop] = options[prop]; | |
| 150 | + return out; | |
| 151 | + } | |
| 152 | + }; | |
| 153 | + | |
| 154 | + function getText(completion) { | |
| 155 | + if (typeof completion == "string") return completion; | |
| 156 | + else return completion.text; | |
| 157 | + } | |
| 158 | + | |
| 159 | + function buildKeyMap(completion, handle) { | |
| 160 | + var baseMap = { | |
| 161 | + Up: function() {handle.moveFocus(-1);}, | |
| 162 | + Down: function() {handle.moveFocus(1);}, | |
| 163 | + PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);}, | |
| 164 | + PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);}, | |
| 165 | + Home: function() {handle.setFocus(0);}, | |
| 166 | + End: function() {handle.setFocus(handle.length - 1);}, | |
| 167 | + Enter: handle.pick, | |
| 168 | + Tab: handle.pick, | |
| 169 | + Esc: handle.close | |
| 170 | + }; | |
| 171 | + var custom = completion.options.customKeys; | |
| 172 | + var ourMap = custom ? {} : baseMap; | |
| 173 | + function addBinding(key, val) { | |
| 174 | + var bound; | |
| 175 | + if (typeof val != "string") | |
| 176 | + bound = function(cm) { return val(cm, handle); }; | |
| 177 | + // This mechanism is deprecated | |
| 178 | + else if (baseMap.hasOwnProperty(val)) | |
| 179 | + bound = baseMap[val]; | |
| 180 | + else | |
| 181 | + bound = val; | |
| 182 | + ourMap[key] = bound; | |
| 183 | + } | |
| 184 | + if (custom) | |
| 185 | + for (var key in custom) if (custom.hasOwnProperty(key)) | |
| 186 | + addBinding(key, custom[key]); | |
| 187 | + var extra = completion.options.extraKeys; | |
| 188 | + if (extra) | |
| 189 | + for (var key in extra) if (extra.hasOwnProperty(key)) | |
| 190 | + addBinding(key, extra[key]); | |
| 191 | + return ourMap; | |
| 192 | + } | |
| 193 | + | |
| 194 | + function getHintElement(hintsElement, el) { | |
| 195 | + while (el && el != hintsElement) { | |
| 196 | + if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el; | |
| 197 | + el = el.parentNode; | |
| 198 | + } | |
| 199 | + } | |
| 200 | + | |
| 201 | + function Widget(completion, data) { | |
| 202 | + this.completion = completion; | |
| 203 | + this.data = data; | |
| 204 | + var widget = this, cm = completion.cm; | |
| 205 | + | |
| 206 | + var hints = this.hints = document.createElement("ul"); | |
| 207 | + hints.className = "CodeMirror-hints"; | |
| 208 | + this.selectedHint = data.selectedHint || 0; | |
| 209 | + | |
| 210 | + var completions = data.list; | |
| 211 | + for (var i = 0; i < completions.length; ++i) { | |
| 212 | + var elt = hints.appendChild(document.createElement("li")), cur = completions[i]; | |
| 213 | + var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS); | |
| 214 | + if (cur.className != null) className = cur.className + " " + className; | |
| 215 | + elt.className = className; | |
| 216 | + if (cur.render) cur.render(elt, data, cur); | |
| 217 | + else elt.appendChild(document.createTextNode(cur.displayText || getText(cur))); | |
| 218 | + elt.hintId = i; | |
| 219 | + } | |
| 220 | + | |
| 221 | + var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null); | |
| 222 | + var left = pos.left, top = pos.bottom, below = true; | |
| 223 | + hints.style.left = left + "px"; | |
| 224 | + hints.style.top = top + "px"; | |
| 225 | + // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. | |
| 226 | + var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); | |
| 227 | + var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight); | |
| 228 | + (completion.options.container || document.body).appendChild(hints); | |
| 229 | + var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH; | |
| 230 | + if (overlapY > 0) { | |
| 231 | + var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top); | |
| 232 | + if (curTop - height > 0) { // Fits above cursor | |
| 233 | + hints.style.top = (top = pos.top - height) + "px"; | |
| 234 | + below = false; | |
| 235 | + } else if (height > winH) { | |
| 236 | + hints.style.height = (winH - 5) + "px"; | |
| 237 | + hints.style.top = (top = pos.bottom - box.top) + "px"; | |
| 238 | + var cursor = cm.getCursor(); | |
| 239 | + if (data.from.ch != cursor.ch) { | |
| 240 | + pos = cm.cursorCoords(cursor); | |
| 241 | + hints.style.left = (left = pos.left) + "px"; | |
| 242 | + box = hints.getBoundingClientRect(); | |
| 243 | + } | |
| 244 | + } | |
| 245 | + } | |
| 246 | + var overlapX = box.left - winW; | |
| 247 | + if (overlapX > 0) { | |
| 248 | + if (box.right - box.left > winW) { | |
| 249 | + hints.style.width = (winW - 5) + "px"; | |
| 250 | + overlapX -= (box.right - box.left) - winW; | |
| 251 | + } | |
| 252 | + hints.style.left = (left = pos.left - overlapX) + "px"; | |
| 253 | + } | |
| 254 | + | |
| 255 | + cm.addKeyMap(this.keyMap = buildKeyMap(completion, { | |
| 256 | + moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); }, | |
| 257 | + setFocus: function(n) { widget.changeActive(n); }, | |
| 258 | + menuSize: function() { return widget.screenAmount(); }, | |
| 259 | + length: completions.length, | |
| 260 | + close: function() { completion.close(); }, | |
| 261 | + pick: function() { widget.pick(); }, | |
| 262 | + data: data | |
| 263 | + })); | |
| 264 | + | |
| 265 | + if (completion.options.closeOnUnfocus) { | |
| 266 | + var closingOnBlur; | |
| 267 | + cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); }); | |
| 268 | + cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); }); | |
| 269 | + } | |
| 270 | + | |
| 271 | + var startScroll = cm.getScrollInfo(); | |
| 272 | + cm.on("scroll", this.onScroll = function() { | |
| 273 | + var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect(); | |
| 274 | + var newTop = top + startScroll.top - curScroll.top; | |
| 275 | + var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop); | |
| 276 | + if (!below) point += hints.offsetHeight; | |
| 277 | + if (point <= editor.top || point >= editor.bottom) return completion.close(); | |
| 278 | + hints.style.top = newTop + "px"; | |
| 279 | + hints.style.left = (left + startScroll.left - curScroll.left) + "px"; | |
| 280 | + }); | |
| 281 | + | |
| 282 | + CodeMirror.on(hints, "dblclick", function(e) { | |
| 283 | + var t = getHintElement(hints, e.target || e.srcElement); | |
| 284 | + if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();} | |
| 285 | + }); | |
| 286 | + | |
| 287 | + CodeMirror.on(hints, "click", function(e) { | |
| 288 | + var t = getHintElement(hints, e.target || e.srcElement); | |
| 289 | + if (t && t.hintId != null) { | |
| 290 | + widget.changeActive(t.hintId); | |
| 291 | + if (completion.options.completeOnSingleClick) widget.pick(); | |
| 292 | + } | |
| 293 | + }); | |
| 294 | + | |
| 295 | + CodeMirror.on(hints, "mousedown", function() { | |
| 296 | + setTimeout(function(){cm.focus();}, 20); | |
| 297 | + }); | |
| 298 | + | |
| 299 | + CodeMirror.signal(data, "select", completions[0], hints.firstChild); | |
| 300 | + return true; | |
| 301 | + } | |
| 302 | + | |
| 303 | + Widget.prototype = { | |
| 304 | + close: function() { | |
| 305 | + if (this.completion.widget != this) return; | |
| 306 | + this.completion.widget = null; | |
| 307 | + this.hints.parentNode.removeChild(this.hints); | |
| 308 | + this.completion.cm.removeKeyMap(this.keyMap); | |
| 309 | + | |
| 310 | + var cm = this.completion.cm; | |
| 311 | + if (this.completion.options.closeOnUnfocus) { | |
| 312 | + cm.off("blur", this.onBlur); | |
| 313 | + cm.off("focus", this.onFocus); | |
| 314 | + } | |
| 315 | + cm.off("scroll", this.onScroll); | |
| 316 | + }, | |
| 317 | + | |
| 318 | + pick: function() { | |
| 319 | + this.completion.pick(this.data, this.selectedHint); | |
| 320 | + }, | |
| 321 | + | |
| 322 | + changeActive: function(i, avoidWrap) { | |
| 323 | + if (i >= this.data.list.length) | |
| 324 | + i = avoidWrap ? this.data.list.length - 1 : 0; | |
| 325 | + else if (i < 0) | |
| 326 | + i = avoidWrap ? 0 : this.data.list.length - 1; | |
| 327 | + if (this.selectedHint == i) return; | |
| 328 | + var node = this.hints.childNodes[this.selectedHint]; | |
| 329 | + node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, ""); | |
| 330 | + node = this.hints.childNodes[this.selectedHint = i]; | |
| 331 | + node.className += " " + ACTIVE_HINT_ELEMENT_CLASS; | |
| 332 | + if (node.offsetTop < this.hints.scrollTop) | |
| 333 | + this.hints.scrollTop = node.offsetTop - 3; | |
| 334 | + else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight) | |
| 335 | + this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3; | |
| 336 | + CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node); | |
| 337 | + }, | |
| 338 | + | |
| 339 | + screenAmount: function() { | |
| 340 | + return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1; | |
| 341 | + } | |
| 342 | + }; | |
| 343 | + | |
| 344 | + CodeMirror.registerHelper("hint", "auto", function(cm, options) { | |
| 345 | + var helpers = cm.getHelpers(cm.getCursor(), "hint"), words; | |
| 346 | + if (helpers.length) { | |
| 347 | + for (var i = 0; i < helpers.length; i++) { | |
| 348 | + var cur = helpers[i](cm, options); | |
| 349 | + if (cur && cur.list.length) return cur; | |
| 350 | + } | |
| 351 | + } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) { | |
| 352 | + if (words) return CodeMirror.hint.fromList(cm, {words: words}); | |
| 353 | + } else if (CodeMirror.hint.anyword) { | |
| 354 | + return CodeMirror.hint.anyword(cm, options); | |
| 355 | + } | |
| 356 | + }); | |
| 357 | + | |
| 358 | + CodeMirror.registerHelper("hint", "fromList", function(cm, options) { | |
| 359 | + var cur = cm.getCursor(), token = cm.getTokenAt(cur); | |
| 360 | + var found = []; | |
| 361 | + for (var i = 0; i < options.words.length; i++) { | |
| 362 | + var word = options.words[i]; | |
| 363 | + if (word.slice(0, token.string.length) == token.string) | |
| 364 | + found.push(word); | |
| 365 | + } | |
| 366 | + | |
| 367 | + if (found.length) return { | |
| 368 | + list: found, | |
| 369 | + from: CodeMirror.Pos(cur.line, token.start), | |
| 370 | + to: CodeMirror.Pos(cur.line, token.end) | |
| 371 | + }; | |
| 372 | + }); | |
| 373 | + | |
| 374 | + CodeMirror.commands.autocomplete = CodeMirror.showHint; | |
| 375 | + | |
| 376 | + var defaultOptions = { | |
| 377 | + hint: CodeMirror.hint.auto, | |
| 378 | + completeSingle: true, | |
| 379 | + alignWithWord: true, | |
| 380 | + closeCharacters: /[\s()\[\]{};:>,]/, | |
| 381 | + closeOnUnfocus: true, | |
| 382 | + completeOnSingleClick: false, | |
| 383 | + container: null, | |
| 384 | + customKeys: null, | |
| 385 | + extraKeys: null | |
| 386 | + }; | |
| 387 | + | |
| 388 | + CodeMirror.defineOption("hintOptions", null); | |
| 389 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,160 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror"), require("../../mode/sql/sql")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror", "../../mode/sql/sql"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + "use strict"; | |
| 13 | + | |
| 14 | + var tables; | |
| 15 | + var keywords; | |
| 16 | + var CONS = { | |
| 17 | + QUERY_DIV: ";", | |
| 18 | + ALIAS_KEYWORD: "AS" | |
| 19 | + }; | |
| 20 | + var Pos = CodeMirror.Pos; | |
| 21 | + | |
| 22 | + function getKeywords(editor) { | |
| 23 | + var mode = editor.doc.modeOption; | |
| 24 | + if (mode === "sql") mode = "text/x-sql"; | |
| 25 | + return CodeMirror.resolveMode(mode).keywords; | |
| 26 | + } | |
| 27 | + | |
| 28 | + function match(string, word) { | |
| 29 | + var len = string.length; | |
| 30 | + var sub = word.substr(0, len); | |
| 31 | + return string.toUpperCase() === sub.toUpperCase(); | |
| 32 | + } | |
| 33 | + | |
| 34 | + function addMatches(result, search, wordlist, formatter) { | |
| 35 | + for (var word in wordlist) { | |
| 36 | + if (!wordlist.hasOwnProperty(word)) continue; | |
| 37 | + if (Array.isArray(wordlist)) { | |
| 38 | + word = wordlist[word]; | |
| 39 | + } | |
| 40 | + if (match(search, word)) { | |
| 41 | + result.push(formatter(word)); | |
| 42 | + } | |
| 43 | + } | |
| 44 | + } | |
| 45 | + | |
| 46 | + function columnCompletion(result, editor) { | |
| 47 | + var cur = editor.getCursor(); | |
| 48 | + var token = editor.getTokenAt(cur); | |
| 49 | + var string = token.string.substr(1); | |
| 50 | + var prevCur = Pos(cur.line, token.start); | |
| 51 | + var table = editor.getTokenAt(prevCur).string; | |
| 52 | + if (!tables.hasOwnProperty(table)) | |
| 53 | + table = findTableByAlias(table, editor); | |
| 54 | + var columns = tables[table]; | |
| 55 | + if (!columns) return; | |
| 56 | + | |
| 57 | + addMatches(result, string, columns, function(w) {return "." + w;}); | |
| 58 | + } | |
| 59 | + | |
| 60 | + function eachWord(lineText, f) { | |
| 61 | + if (!lineText) return; | |
| 62 | + var excepted = /[,;]/g; | |
| 63 | + var words = lineText.split(" "); | |
| 64 | + for (var i = 0; i < words.length; i++) { | |
| 65 | + f(words[i]?words[i].replace(excepted, '') : ''); | |
| 66 | + } | |
| 67 | + } | |
| 68 | + | |
| 69 | + function convertCurToNumber(cur) { | |
| 70 | + // max characters of a line is 999,999. | |
| 71 | + return cur.line + cur.ch / Math.pow(10, 6); | |
| 72 | + } | |
| 73 | + | |
| 74 | + function convertNumberToCur(num) { | |
| 75 | + return Pos(Math.floor(num), +num.toString().split('.').pop()); | |
| 76 | + } | |
| 77 | + | |
| 78 | + function findTableByAlias(alias, editor) { | |
| 79 | + var doc = editor.doc; | |
| 80 | + var fullQuery = doc.getValue(); | |
| 81 | + var aliasUpperCase = alias.toUpperCase(); | |
| 82 | + var previousWord = ""; | |
| 83 | + var table = ""; | |
| 84 | + var separator = []; | |
| 85 | + var validRange = { | |
| 86 | + start: Pos(0, 0), | |
| 87 | + end: Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).length) | |
| 88 | + }; | |
| 89 | + | |
| 90 | + //add separator | |
| 91 | + var indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV); | |
| 92 | + while(indexOfSeparator != -1) { | |
| 93 | + separator.push(doc.posFromIndex(indexOfSeparator)); | |
| 94 | + indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV, indexOfSeparator+1); | |
| 95 | + } | |
| 96 | + separator.unshift(Pos(0, 0)); | |
| 97 | + separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length)); | |
| 98 | + | |
| 99 | + //find valid range | |
| 100 | + var prevItem = 0; | |
| 101 | + var current = convertCurToNumber(editor.getCursor()); | |
| 102 | + for (var i=0; i< separator.length; i++) { | |
| 103 | + var _v = convertCurToNumber(separator[i]); | |
| 104 | + if (current > prevItem && current <= _v) { | |
| 105 | + validRange = { start: convertNumberToCur(prevItem), end: convertNumberToCur(_v) }; | |
| 106 | + break; | |
| 107 | + } | |
| 108 | + prevItem = _v; | |
| 109 | + } | |
| 110 | + | |
| 111 | + var query = doc.getRange(validRange.start, validRange.end, false); | |
| 112 | + | |
| 113 | + for (var i = 0; i < query.length; i++) { | |
| 114 | + var lineText = query[i]; | |
| 115 | + eachWord(lineText, function(word) { | |
| 116 | + var wordUpperCase = word.toUpperCase(); | |
| 117 | + if (wordUpperCase === aliasUpperCase && tables.hasOwnProperty(previousWord)) { | |
| 118 | + table = previousWord; | |
| 119 | + } | |
| 120 | + if (wordUpperCase !== CONS.ALIAS_KEYWORD) { | |
| 121 | + previousWord = word; | |
| 122 | + } | |
| 123 | + }); | |
| 124 | + if (table) break; | |
| 125 | + } | |
| 126 | + return table; | |
| 127 | + } | |
| 128 | + | |
| 129 | + CodeMirror.registerHelper("hint", "sql", function(editor, options) { | |
| 130 | + tables = (options && options.tables) || {}; | |
| 131 | + keywords = keywords || getKeywords(editor); | |
| 132 | + var cur = editor.getCursor(); | |
| 133 | + var result = []; | |
| 134 | + var token = editor.getTokenAt(cur), start, end, search; | |
| 135 | + if (token.string.match(/^[.\w@]\w*$/)) { | |
| 136 | + search = token.string; | |
| 137 | + start = token.start; | |
| 138 | + end = token.end; | |
| 139 | + } else { | |
| 140 | + start = end = cur.ch; | |
| 141 | + search = ""; | |
| 142 | + } | |
| 143 | + if (search.charAt(0) == ".") { | |
| 144 | + columnCompletion(result, editor); | |
| 145 | + if (!result.length) { | |
| 146 | + while (start && search.charAt(0) == ".") { | |
| 147 | + token = editor.getTokenAt(Pos(cur.line, token.start - 1)); | |
| 148 | + start = token.start; | |
| 149 | + search = token.string + search; | |
| 150 | + } | |
| 151 | + addMatches(result, search, tables, function(w) {return w;}); | |
| 152 | + } | |
| 153 | + } else { | |
| 154 | + addMatches(result, search, tables, function(w) {return w;}); | |
| 155 | + addMatches(result, search, keywords, function(w) {return w.toUpperCase();}); | |
| 156 | + } | |
| 157 | + | |
| 158 | + return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)}; | |
| 159 | + }); | |
| 160 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,103 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + "use strict"; | |
| 13 | + | |
| 14 | + var Pos = CodeMirror.Pos; | |
| 15 | + | |
| 16 | + function getHints(cm, options) { | |
| 17 | + var tags = options && options.schemaInfo; | |
| 18 | + var quote = (options && options.quoteChar) || '"'; | |
| 19 | + if (!tags) return; | |
| 20 | + var cur = cm.getCursor(), token = cm.getTokenAt(cur); | |
| 21 | + var inner = CodeMirror.innerMode(cm.getMode(), token.state); | |
| 22 | + if (inner.mode.name != "xml") return; | |
| 23 | + var result = [], replaceToken = false, prefix; | |
| 24 | + var tag = /\btag\b/.test(token.type), tagName = tag && /^\w/.test(token.string), tagStart; | |
| 25 | + if (tagName) { | |
| 26 | + var before = cm.getLine(cur.line).slice(Math.max(0, token.start - 2), token.start); | |
| 27 | + var tagType = /<\/$/.test(before) ? "close" : /<$/.test(before) ? "open" : null; | |
| 28 | + if (tagType) tagStart = token.start - (tagType == "close" ? 2 : 1); | |
| 29 | + } else if (tag && token.string == "<") { | |
| 30 | + tagType = "open"; | |
| 31 | + } else if (tag && token.string == "</") { | |
| 32 | + tagType = "close"; | |
| 33 | + } | |
| 34 | + if (!tag && !inner.state.tagName || tagType) { | |
| 35 | + if (tagName) | |
| 36 | + prefix = token.string; | |
| 37 | + replaceToken = tagType; | |
| 38 | + var cx = inner.state.context, curTag = cx && tags[cx.tagName]; | |
| 39 | + var childList = cx ? curTag && curTag.children : tags["!top"]; | |
| 40 | + if (childList && tagType != "close") { | |
| 41 | + for (var i = 0; i < childList.length; ++i) if (!prefix || childList[i].lastIndexOf(prefix, 0) == 0) | |
| 42 | + result.push("<" + childList[i]); | |
| 43 | + } else if (tagType != "close") { | |
| 44 | + for (var name in tags) | |
| 45 | + if (tags.hasOwnProperty(name) && name != "!top" && name != "!attrs" && (!prefix || name.lastIndexOf(prefix, 0) == 0)) | |
| 46 | + result.push("<" + name); | |
| 47 | + } | |
| 48 | + if (cx && (!prefix || tagType == "close" && cx.tagName.lastIndexOf(prefix, 0) == 0)) | |
| 49 | + result.push("</" + cx.tagName + ">"); | |
| 50 | + } else { | |
| 51 | + // Attribute completion | |
| 52 | + var curTag = tags[inner.state.tagName], attrs = curTag && curTag.attrs; | |
| 53 | + var globalAttrs = tags["!attrs"]; | |
| 54 | + if (!attrs && !globalAttrs) return; | |
| 55 | + if (!attrs) { | |
| 56 | + attrs = globalAttrs; | |
| 57 | + } else if (globalAttrs) { // Combine tag-local and global attributes | |
| 58 | + var set = {}; | |
| 59 | + for (var nm in globalAttrs) if (globalAttrs.hasOwnProperty(nm)) set[nm] = globalAttrs[nm]; | |
| 60 | + for (var nm in attrs) if (attrs.hasOwnProperty(nm)) set[nm] = attrs[nm]; | |
| 61 | + attrs = set; | |
| 62 | + } | |
| 63 | + if (token.type == "string" || token.string == "=") { // A value | |
| 64 | + var before = cm.getRange(Pos(cur.line, Math.max(0, cur.ch - 60)), | |
| 65 | + Pos(cur.line, token.type == "string" ? token.start : token.end)); | |
| 66 | + var atName = before.match(/([^\s\u00a0=<>\"\']+)=$/), atValues; | |
| 67 | + if (!atName || !attrs.hasOwnProperty(atName[1]) || !(atValues = attrs[atName[1]])) return; | |
| 68 | + if (typeof atValues == 'function') atValues = atValues.call(this, cm); // Functions can be used to supply values for autocomplete widget | |
| 69 | + if (token.type == "string") { | |
| 70 | + prefix = token.string; | |
| 71 | + var n = 0; | |
| 72 | + if (/['"]/.test(token.string.charAt(0))) { | |
| 73 | + quote = token.string.charAt(0); | |
| 74 | + prefix = token.string.slice(1); | |
| 75 | + n++; | |
| 76 | + } | |
| 77 | + var len = token.string.length; | |
| 78 | + if (/['"]/.test(token.string.charAt(len - 1))) { | |
| 79 | + quote = token.string.charAt(len - 1); | |
| 80 | + prefix = token.string.substr(n, len - 2); | |
| 81 | + } | |
| 82 | + replaceToken = true; | |
| 83 | + } | |
| 84 | + for (var i = 0; i < atValues.length; ++i) if (!prefix || atValues[i].lastIndexOf(prefix, 0) == 0) | |
| 85 | + result.push(quote + atValues[i] + quote); | |
| 86 | + } else { // An attribute name | |
| 87 | + if (token.type == "attribute") { | |
| 88 | + prefix = token.string; | |
| 89 | + replaceToken = true; | |
| 90 | + } | |
| 91 | + for (var attr in attrs) if (attrs.hasOwnProperty(attr) && (!prefix || attr.lastIndexOf(prefix, 0) == 0)) | |
| 92 | + result.push(attr); | |
| 93 | + } | |
| 94 | + } | |
| 95 | + return { | |
| 96 | + list: result, | |
| 97 | + from: replaceToken ? Pos(cur.line, tagStart == null ? token.start : tagStart) : cur, | |
| 98 | + to: replaceToken ? Pos(cur.line, token.end) : cur | |
| 99 | + }; | |
| 100 | + } | |
| 101 | + | |
| 102 | + CodeMirror.registerHelper("hint", "xml", getHints); | |
| 103 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,41 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +// Depends on coffeelint.js from http://www.coffeelint.org/js/coffeelint.js | |
| 5 | + | |
| 6 | +// declare global: coffeelint | |
| 7 | + | |
| 8 | +(function(mod) { | |
| 9 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 10 | + mod(require("../../lib/codemirror")); | |
| 11 | + else if (typeof define == "function" && define.amd) // AMD | |
| 12 | + define(["../../lib/codemirror"], mod); | |
| 13 | + else // Plain browser env | |
| 14 | + mod(CodeMirror); | |
| 15 | +})(function(CodeMirror) { | |
| 16 | +"use strict"; | |
| 17 | + | |
| 18 | +CodeMirror.registerHelper("lint", "coffeescript", function(text) { | |
| 19 | + var found = []; | |
| 20 | + var parseError = function(err) { | |
| 21 | + var loc = err.lineNumber; | |
| 22 | + found.push({from: CodeMirror.Pos(loc-1, 0), | |
| 23 | + to: CodeMirror.Pos(loc, 0), | |
| 24 | + severity: err.level, | |
| 25 | + message: err.message}); | |
| 26 | + }; | |
| 27 | + try { | |
| 28 | + var res = coffeelint.lint(text); | |
| 29 | + for(var i = 0; i < res.length; i++) { | |
| 30 | + parseError(res[i]); | |
| 31 | + } | |
| 32 | + } catch(e) { | |
| 33 | + found.push({from: CodeMirror.Pos(e.location.first_line, 0), | |
| 34 | + to: CodeMirror.Pos(e.location.last_line, e.location.last_column), | |
| 35 | + severity: 'error', | |
| 36 | + message: e.message}); | |
| 37 | + } | |
| 38 | + return found; | |
| 39 | +}); | |
| 40 | + | |
| 41 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,35 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +// Depends on csslint.js from https://github.com/stubbornella/csslint | |
| 5 | + | |
| 6 | +// declare global: CSSLint | |
| 7 | + | |
| 8 | +(function(mod) { | |
| 9 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 10 | + mod(require("../../lib/codemirror")); | |
| 11 | + else if (typeof define == "function" && define.amd) // AMD | |
| 12 | + define(["../../lib/codemirror"], mod); | |
| 13 | + else // Plain browser env | |
| 14 | + mod(CodeMirror); | |
| 15 | +})(function(CodeMirror) { | |
| 16 | +"use strict"; | |
| 17 | + | |
| 18 | +CodeMirror.registerHelper("lint", "css", function(text) { | |
| 19 | + var found = []; | |
| 20 | + if (!window.CSSLint) return found; | |
| 21 | + var results = CSSLint.verify(text), messages = results.messages, message = null; | |
| 22 | + for ( var i = 0; i < messages.length; i++) { | |
| 23 | + message = messages[i]; | |
| 24 | + var startLine = message.line -1, endLine = message.line -1, startCol = message.col -1, endCol = message.col; | |
| 25 | + found.push({ | |
| 26 | + from: CodeMirror.Pos(startLine, startCol), | |
| 27 | + to: CodeMirror.Pos(endLine, endCol), | |
| 28 | + message: message.message, | |
| 29 | + severity : message.type | |
| 30 | + }); | |
| 31 | + } | |
| 32 | + return found; | |
| 33 | +}); | |
| 34 | + | |
| 35 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,136 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + "use strict"; | |
| 13 | + // declare global: JSHINT | |
| 14 | + | |
| 15 | + var bogus = [ "Dangerous comment" ]; | |
| 16 | + | |
| 17 | + var warnings = [ [ "Expected '{'", | |
| 18 | + "Statement body should be inside '{ }' braces." ] ]; | |
| 19 | + | |
| 20 | + var errors = [ "Missing semicolon", "Extra comma", "Missing property name", | |
| 21 | + "Unmatched ", " and instead saw", " is not defined", | |
| 22 | + "Unclosed string", "Stopping, unable to continue" ]; | |
| 23 | + | |
| 24 | + function validator(text, options) { | |
| 25 | + if (!window.JSHINT) return []; | |
| 26 | + JSHINT(text, options); | |
| 27 | + var errors = JSHINT.data().errors, result = []; | |
| 28 | + if (errors) parseErrors(errors, result); | |
| 29 | + return result; | |
| 30 | + } | |
| 31 | + | |
| 32 | + CodeMirror.registerHelper("lint", "javascript", validator); | |
| 33 | + | |
| 34 | + function cleanup(error) { | |
| 35 | + // All problems are warnings by default | |
| 36 | + fixWith(error, warnings, "warning", true); | |
| 37 | + fixWith(error, errors, "error"); | |
| 38 | + | |
| 39 | + return isBogus(error) ? null : error; | |
| 40 | + } | |
| 41 | + | |
| 42 | + function fixWith(error, fixes, severity, force) { | |
| 43 | + var description, fix, find, replace, found; | |
| 44 | + | |
| 45 | + description = error.description; | |
| 46 | + | |
| 47 | + for ( var i = 0; i < fixes.length; i++) { | |
| 48 | + fix = fixes[i]; | |
| 49 | + find = (typeof fix === "string" ? fix : fix[0]); | |
| 50 | + replace = (typeof fix === "string" ? null : fix[1]); | |
| 51 | + found = description.indexOf(find) !== -1; | |
| 52 | + | |
| 53 | + if (force || found) { | |
| 54 | + error.severity = severity; | |
| 55 | + } | |
| 56 | + if (found && replace) { | |
| 57 | + error.description = replace; | |
| 58 | + } | |
| 59 | + } | |
| 60 | + } | |
| 61 | + | |
| 62 | + function isBogus(error) { | |
| 63 | + var description = error.description; | |
| 64 | + for ( var i = 0; i < bogus.length; i++) { | |
| 65 | + if (description.indexOf(bogus[i]) !== -1) { | |
| 66 | + return true; | |
| 67 | + } | |
| 68 | + } | |
| 69 | + return false; | |
| 70 | + } | |
| 71 | + | |
| 72 | + function parseErrors(errors, output) { | |
| 73 | + for ( var i = 0; i < errors.length; i++) { | |
| 74 | + var error = errors[i]; | |
| 75 | + if (error) { | |
| 76 | + var linetabpositions, index; | |
| 77 | + | |
| 78 | + linetabpositions = []; | |
| 79 | + | |
| 80 | + // This next block is to fix a problem in jshint. Jshint | |
| 81 | + // replaces | |
| 82 | + // all tabs with spaces then performs some checks. The error | |
| 83 | + // positions (character/space) are then reported incorrectly, | |
| 84 | + // not taking the replacement step into account. Here we look | |
| 85 | + // at the evidence line and try to adjust the character position | |
| 86 | + // to the correct value. | |
| 87 | + if (error.evidence) { | |
| 88 | + // Tab positions are computed once per line and cached | |
| 89 | + var tabpositions = linetabpositions[error.line]; | |
| 90 | + if (!tabpositions) { | |
| 91 | + var evidence = error.evidence; | |
| 92 | + tabpositions = []; | |
| 93 | + // ugggh phantomjs does not like this | |
| 94 | + // forEachChar(evidence, function(item, index) { | |
| 95 | + Array.prototype.forEach.call(evidence, function(item, | |
| 96 | + index) { | |
| 97 | + if (item === '\t') { | |
| 98 | + // First col is 1 (not 0) to match error | |
| 99 | + // positions | |
| 100 | + tabpositions.push(index + 1); | |
| 101 | + } | |
| 102 | + }); | |
| 103 | + linetabpositions[error.line] = tabpositions; | |
| 104 | + } | |
| 105 | + if (tabpositions.length > 0) { | |
| 106 | + var pos = error.character; | |
| 107 | + tabpositions.forEach(function(tabposition) { | |
| 108 | + if (pos > tabposition) pos -= 1; | |
| 109 | + }); | |
| 110 | + error.character = pos; | |
| 111 | + } | |
| 112 | + } | |
| 113 | + | |
| 114 | + var start = error.character - 1, end = start + 1; | |
| 115 | + if (error.evidence) { | |
| 116 | + index = error.evidence.substring(start).search(/.\b/); | |
| 117 | + if (index > -1) { | |
| 118 | + end += index; | |
| 119 | + } | |
| 120 | + } | |
| 121 | + | |
| 122 | + // Convert to format expected by validation service | |
| 123 | + error.description = error.reason;// + "(jshint)"; | |
| 124 | + error.start = error.character; | |
| 125 | + error.end = end; | |
| 126 | + error = cleanup(error); | |
| 127 | + | |
| 128 | + if (error) | |
| 129 | + output.push({message: error.description, | |
| 130 | + severity: error.severity, | |
| 131 | + from: CodeMirror.Pos(error.line - 1, start), | |
| 132 | + to: CodeMirror.Pos(error.line - 1, end)}); | |
| 133 | + } | |
| 134 | + } | |
| 135 | + } | |
| 136 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,31 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +// Depends on jsonlint.js from https://github.com/zaach/jsonlint | |
| 5 | + | |
| 6 | +// declare global: jsonlint | |
| 7 | + | |
| 8 | +(function(mod) { | |
| 9 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 10 | + mod(require("../../lib/codemirror")); | |
| 11 | + else if (typeof define == "function" && define.amd) // AMD | |
| 12 | + define(["../../lib/codemirror"], mod); | |
| 13 | + else // Plain browser env | |
| 14 | + mod(CodeMirror); | |
| 15 | +})(function(CodeMirror) { | |
| 16 | +"use strict"; | |
| 17 | + | |
| 18 | +CodeMirror.registerHelper("lint", "json", function(text) { | |
| 19 | + var found = []; | |
| 20 | + jsonlint.parseError = function(str, hash) { | |
| 21 | + var loc = hash.loc; | |
| 22 | + found.push({from: CodeMirror.Pos(loc.first_line - 1, loc.first_column), | |
| 23 | + to: CodeMirror.Pos(loc.last_line - 1, loc.last_column), | |
| 24 | + message: str}); | |
| 25 | + }; | |
| 26 | + try { jsonlint.parse(text); } | |
| 27 | + catch(e) {} | |
| 28 | + return found; | |
| 29 | +}); | |
| 30 | + | |
| 31 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,73 @@ |
| 1 | +/* The lint marker gutter */ | |
| 2 | +.CodeMirror-lint-markers { | |
| 3 | + width: 16px; | |
| 4 | +} | |
| 5 | + | |
| 6 | +.CodeMirror-lint-tooltip { | |
| 7 | + background-color: infobackground; | |
| 8 | + border: 1px solid black; | |
| 9 | + border-radius: 4px 4px 4px 4px; | |
| 10 | + color: infotext; | |
| 11 | + font-family: monospace; | |
| 12 | + font-size: 10pt; | |
| 13 | + overflow: hidden; | |
| 14 | + padding: 2px 5px; | |
| 15 | + position: fixed; | |
| 16 | + white-space: pre; | |
| 17 | + white-space: pre-wrap; | |
| 18 | + z-index: 100; | |
| 19 | + max-width: 600px; | |
| 20 | + opacity: 0; | |
| 21 | + transition: opacity .4s; | |
| 22 | + -moz-transition: opacity .4s; | |
| 23 | + -webkit-transition: opacity .4s; | |
| 24 | + -o-transition: opacity .4s; | |
| 25 | + -ms-transition: opacity .4s; | |
| 26 | +} | |
| 27 | + | |
| 28 | +.CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning { | |
| 29 | + background-position: left bottom; | |
| 30 | + background-repeat: repeat-x; | |
| 31 | +} | |
| 32 | + | |
| 33 | +.CodeMirror-lint-mark-error { | |
| 34 | + background-image: | |
| 35 | + url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==") | |
| 36 | + ; | |
| 37 | +} | |
| 38 | + | |
| 39 | +.CodeMirror-lint-mark-warning { | |
| 40 | + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII="); | |
| 41 | +} | |
| 42 | + | |
| 43 | +.CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning { | |
| 44 | + background-position: center center; | |
| 45 | + background-repeat: no-repeat; | |
| 46 | + cursor: pointer; | |
| 47 | + display: inline-block; | |
| 48 | + height: 16px; | |
| 49 | + width: 16px; | |
| 50 | + vertical-align: middle; | |
| 51 | + position: relative; | |
| 52 | +} | |
| 53 | + | |
| 54 | +.CodeMirror-lint-message-error, .CodeMirror-lint-message-warning { | |
| 55 | + padding-left: 18px; | |
| 56 | + background-position: top left; | |
| 57 | + background-repeat: no-repeat; | |
| 58 | +} | |
| 59 | + | |
| 60 | +.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error { | |
| 61 | + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII="); | |
| 62 | +} | |
| 63 | + | |
| 64 | +.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning { | |
| 65 | + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII="); | |
| 66 | +} | |
| 67 | + | |
| 68 | +.CodeMirror-lint-marker-multiple { | |
| 69 | + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC"); | |
| 70 | + background-repeat: no-repeat; | |
| 71 | + background-position: right bottom; | |
| 72 | + width: 100%; height: 100%; | |
| 73 | +} | ... | ... |
| ... | ... | @@ -0,0 +1,209 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + "use strict"; | |
| 13 | + var GUTTER_ID = "CodeMirror-lint-markers"; | |
| 14 | + | |
| 15 | + function showTooltip(e, content) { | |
| 16 | + var tt = document.createElement("div"); | |
| 17 | + tt.className = "CodeMirror-lint-tooltip"; | |
| 18 | + tt.appendChild(content.cloneNode(true)); | |
| 19 | + document.body.appendChild(tt); | |
| 20 | + | |
| 21 | + function position(e) { | |
| 22 | + if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position); | |
| 23 | + tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px"; | |
| 24 | + tt.style.left = (e.clientX + 5) + "px"; | |
| 25 | + } | |
| 26 | + CodeMirror.on(document, "mousemove", position); | |
| 27 | + position(e); | |
| 28 | + if (tt.style.opacity != null) tt.style.opacity = 1; | |
| 29 | + return tt; | |
| 30 | + } | |
| 31 | + function rm(elt) { | |
| 32 | + if (elt.parentNode) elt.parentNode.removeChild(elt); | |
| 33 | + } | |
| 34 | + function hideTooltip(tt) { | |
| 35 | + if (!tt.parentNode) return; | |
| 36 | + if (tt.style.opacity == null) rm(tt); | |
| 37 | + tt.style.opacity = 0; | |
| 38 | + setTimeout(function() { rm(tt); }, 600); | |
| 39 | + } | |
| 40 | + | |
| 41 | + function showTooltipFor(e, content, node) { | |
| 42 | + var tooltip = showTooltip(e, content); | |
| 43 | + function hide() { | |
| 44 | + CodeMirror.off(node, "mouseout", hide); | |
| 45 | + if (tooltip) { hideTooltip(tooltip); tooltip = null; } | |
| 46 | + } | |
| 47 | + var poll = setInterval(function() { | |
| 48 | + if (tooltip) for (var n = node;; n = n.parentNode) { | |
| 49 | + if (n == document.body) return; | |
| 50 | + if (!n) { hide(); break; } | |
| 51 | + } | |
| 52 | + if (!tooltip) return clearInterval(poll); | |
| 53 | + }, 400); | |
| 54 | + CodeMirror.on(node, "mouseout", hide); | |
| 55 | + } | |
| 56 | + | |
| 57 | + function LintState(cm, options, hasGutter) { | |
| 58 | + this.marked = []; | |
| 59 | + this.options = options; | |
| 60 | + this.timeout = null; | |
| 61 | + this.hasGutter = hasGutter; | |
| 62 | + this.onMouseOver = function(e) { onMouseOver(cm, e); }; | |
| 63 | + } | |
| 64 | + | |
| 65 | + function parseOptions(cm, options) { | |
| 66 | + if (options instanceof Function) return {getAnnotations: options}; | |
| 67 | + if (!options || options === true) options = {}; | |
| 68 | + if (!options.getAnnotations) options.getAnnotations = cm.getHelper(CodeMirror.Pos(0, 0), "lint"); | |
| 69 | + if (!options.getAnnotations) throw new Error("Required option 'getAnnotations' missing (lint addon)"); | |
| 70 | + return options; | |
| 71 | + } | |
| 72 | + | |
| 73 | + function clearMarks(cm) { | |
| 74 | + var state = cm.state.lint; | |
| 75 | + if (state.hasGutter) cm.clearGutter(GUTTER_ID); | |
| 76 | + for (var i = 0; i < state.marked.length; ++i) | |
| 77 | + state.marked[i].clear(); | |
| 78 | + state.marked.length = 0; | |
| 79 | + } | |
| 80 | + | |
| 81 | + function makeMarker(labels, severity, multiple, tooltips) { | |
| 82 | + var marker = document.createElement("div"), inner = marker; | |
| 83 | + marker.className = "CodeMirror-lint-marker-" + severity; | |
| 84 | + if (multiple) { | |
| 85 | + inner = marker.appendChild(document.createElement("div")); | |
| 86 | + inner.className = "CodeMirror-lint-marker-multiple"; | |
| 87 | + } | |
| 88 | + | |
| 89 | + if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) { | |
| 90 | + showTooltipFor(e, labels, inner); | |
| 91 | + }); | |
| 92 | + | |
| 93 | + return marker; | |
| 94 | + } | |
| 95 | + | |
| 96 | + function getMaxSeverity(a, b) { | |
| 97 | + if (a == "error") return a; | |
| 98 | + else return b; | |
| 99 | + } | |
| 100 | + | |
| 101 | + function groupByLine(annotations) { | |
| 102 | + var lines = []; | |
| 103 | + for (var i = 0; i < annotations.length; ++i) { | |
| 104 | + var ann = annotations[i], line = ann.from.line; | |
| 105 | + (lines[line] || (lines[line] = [])).push(ann); | |
| 106 | + } | |
| 107 | + return lines; | |
| 108 | + } | |
| 109 | + | |
| 110 | + function annotationTooltip(ann) { | |
| 111 | + var severity = ann.severity; | |
| 112 | + if (!severity) severity = "error"; | |
| 113 | + var tip = document.createElement("div"); | |
| 114 | + tip.className = "CodeMirror-lint-message-" + severity; | |
| 115 | + tip.appendChild(document.createTextNode(ann.message)); | |
| 116 | + return tip; | |
| 117 | + } | |
| 118 | + | |
| 119 | + function startLinting(cm) { | |
| 120 | + var state = cm.state.lint, options = state.options; | |
| 121 | + if (options.async) | |
| 122 | + options.getAnnotations(cm, updateLinting, options); | |
| 123 | + else | |
| 124 | + updateLinting(cm, options.getAnnotations(cm.getValue(), options.options)); | |
| 125 | + } | |
| 126 | + | |
| 127 | + function updateLinting(cm, annotationsNotSorted) { | |
| 128 | + clearMarks(cm); | |
| 129 | + var state = cm.state.lint, options = state.options; | |
| 130 | + | |
| 131 | + var annotations = groupByLine(annotationsNotSorted); | |
| 132 | + | |
| 133 | + for (var line = 0; line < annotations.length; ++line) { | |
| 134 | + var anns = annotations[line]; | |
| 135 | + if (!anns) continue; | |
| 136 | + | |
| 137 | + var maxSeverity = null; | |
| 138 | + var tipLabel = state.hasGutter && document.createDocumentFragment(); | |
| 139 | + | |
| 140 | + for (var i = 0; i < anns.length; ++i) { | |
| 141 | + var ann = anns[i]; | |
| 142 | + var severity = ann.severity; | |
| 143 | + if (!severity) severity = "error"; | |
| 144 | + maxSeverity = getMaxSeverity(maxSeverity, severity); | |
| 145 | + | |
| 146 | + if (options.formatAnnotation) ann = options.formatAnnotation(ann); | |
| 147 | + if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann)); | |
| 148 | + | |
| 149 | + if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, { | |
| 150 | + className: "CodeMirror-lint-mark-" + severity, | |
| 151 | + __annotation: ann | |
| 152 | + })); | |
| 153 | + } | |
| 154 | + | |
| 155 | + if (state.hasGutter) | |
| 156 | + cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1, | |
| 157 | + state.options.tooltips)); | |
| 158 | + } | |
| 159 | + if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm); | |
| 160 | + } | |
| 161 | + | |
| 162 | + function onChange(cm) { | |
| 163 | + var state = cm.state.lint; | |
| 164 | + clearTimeout(state.timeout); | |
| 165 | + state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500); | |
| 166 | + } | |
| 167 | + | |
| 168 | + function popupSpanTooltip(ann, e) { | |
| 169 | + var target = e.target || e.srcElement; | |
| 170 | + showTooltipFor(e, annotationTooltip(ann), target); | |
| 171 | + } | |
| 172 | + | |
| 173 | + // When the mouseover fires, the cursor might not actually be over | |
| 174 | + // the character itself yet. These pairs of x,y offsets are used to | |
| 175 | + // probe a few nearby points when no suitable marked range is found. | |
| 176 | + var nearby = [0, 0, 0, 5, 0, -5, 5, 0, -5, 0]; | |
| 177 | + | |
| 178 | + function onMouseOver(cm, e) { | |
| 179 | + if (!/\bCodeMirror-lint-mark-/.test((e.target || e.srcElement).className)) return; | |
| 180 | + for (var i = 0; i < nearby.length; i += 2) { | |
| 181 | + var spans = cm.findMarksAt(cm.coordsChar({left: e.clientX + nearby[i], | |
| 182 | + top: e.clientY + nearby[i + 1]}, "client")); | |
| 183 | + for (var j = 0; j < spans.length; ++j) { | |
| 184 | + var span = spans[j], ann = span.__annotation; | |
| 185 | + if (ann) return popupSpanTooltip(ann, e); | |
| 186 | + } | |
| 187 | + } | |
| 188 | + } | |
| 189 | + | |
| 190 | + CodeMirror.defineOption("lint", false, function(cm, val, old) { | |
| 191 | + if (old && old != CodeMirror.Init) { | |
| 192 | + clearMarks(cm); | |
| 193 | + cm.off("change", onChange); | |
| 194 | + CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver); | |
| 195 | + delete cm.state.lint; | |
| 196 | + } | |
| 197 | + | |
| 198 | + if (val) { | |
| 199 | + var gutters = cm.getOption("gutters"), hasLintGutter = false; | |
| 200 | + for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true; | |
| 201 | + var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter); | |
| 202 | + cm.on("change", onChange); | |
| 203 | + if (state.options.tooltips != false) | |
| 204 | + CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver); | |
| 205 | + | |
| 206 | + startLinting(cm); | |
| 207 | + } | |
| 208 | + }); | |
| 209 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,28 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | +"use strict"; | |
| 13 | + | |
| 14 | +// Depends on js-yaml.js from https://github.com/nodeca/js-yaml | |
| 15 | + | |
| 16 | +// declare global: jsyaml | |
| 17 | + | |
| 18 | +CodeMirror.registerHelper("lint", "yaml", function(text) { | |
| 19 | + var found = []; | |
| 20 | + try { jsyaml.load(text); } | |
| 21 | + catch(e) { | |
| 22 | + var loc = e.mark; | |
| 23 | + found.push({ from: CodeMirror.Pos(loc.line, loc.column), to: CodeMirror.Pos(loc.line, loc.column), message: e.message }); | |
| 24 | + } | |
| 25 | + return found; | |
| 26 | +}); | |
| 27 | + | |
| 28 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,98 @@ |
| 1 | +.CodeMirror-merge { | |
| 2 | + position: relative; | |
| 3 | + border: 1px solid #ddd; | |
| 4 | + white-space: pre; | |
| 5 | +} | |
| 6 | + | |
| 7 | +.CodeMirror-merge, .CodeMirror-merge .CodeMirror { | |
| 8 | + height: 350px; | |
| 9 | +} | |
| 10 | + | |
| 11 | +.CodeMirror-merge-2pane .CodeMirror-merge-pane { width: 47%; } | |
| 12 | +.CodeMirror-merge-2pane .CodeMirror-merge-gap { width: 6%; } | |
| 13 | +.CodeMirror-merge-3pane .CodeMirror-merge-pane { width: 31%; } | |
| 14 | +.CodeMirror-merge-3pane .CodeMirror-merge-gap { width: 3.5%; } | |
| 15 | + | |
| 16 | +.CodeMirror-merge-pane { | |
| 17 | + display: inline-block; | |
| 18 | + white-space: normal; | |
| 19 | + vertical-align: top; | |
| 20 | +} | |
| 21 | +.CodeMirror-merge-pane-rightmost { | |
| 22 | + position: absolute; | |
| 23 | + right: 0px; | |
| 24 | + z-index: 1; | |
| 25 | +} | |
| 26 | + | |
| 27 | +.CodeMirror-merge-gap { | |
| 28 | + z-index: 2; | |
| 29 | + display: inline-block; | |
| 30 | + height: 100%; | |
| 31 | + -moz-box-sizing: border-box; | |
| 32 | + box-sizing: border-box; | |
| 33 | + overflow: hidden; | |
| 34 | + border-left: 1px solid #ddd; | |
| 35 | + border-right: 1px solid #ddd; | |
| 36 | + position: relative; | |
| 37 | + background: #f8f8f8; | |
| 38 | +} | |
| 39 | + | |
| 40 | +.CodeMirror-merge-scrolllock-wrap { | |
| 41 | + position: absolute; | |
| 42 | + bottom: 0; left: 50%; | |
| 43 | +} | |
| 44 | +.CodeMirror-merge-scrolllock { | |
| 45 | + position: relative; | |
| 46 | + left: -50%; | |
| 47 | + cursor: pointer; | |
| 48 | + color: #555; | |
| 49 | + line-height: 1; | |
| 50 | +} | |
| 51 | + | |
| 52 | +.CodeMirror-merge-copybuttons-left, .CodeMirror-merge-copybuttons-right { | |
| 53 | + position: absolute; | |
| 54 | + left: 0; top: 0; | |
| 55 | + right: 0; bottom: 0; | |
| 56 | + line-height: 1; | |
| 57 | +} | |
| 58 | + | |
| 59 | +.CodeMirror-merge-copy { | |
| 60 | + position: absolute; | |
| 61 | + cursor: pointer; | |
| 62 | + color: #44c; | |
| 63 | +} | |
| 64 | + | |
| 65 | +.CodeMirror-merge-copy-reverse { | |
| 66 | + position: absolute; | |
| 67 | + cursor: pointer; | |
| 68 | + color: #44c; | |
| 69 | +} | |
| 70 | + | |
| 71 | +.CodeMirror-merge-copybuttons-left .CodeMirror-merge-copy { left: 2px; } | |
| 72 | +.CodeMirror-merge-copybuttons-right .CodeMirror-merge-copy { right: 2px; } | |
| 73 | + | |
| 74 | +.CodeMirror-merge-r-inserted, .CodeMirror-merge-l-inserted { | |
| 75 | + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12MwuCXy3+CWyH8GBgYGJgYkAABZbAQ9ELXurwAAAABJRU5ErkJggg==); | |
| 76 | + background-position: bottom left; | |
| 77 | + background-repeat: repeat-x; | |
| 78 | +} | |
| 79 | + | |
| 80 | +.CodeMirror-merge-r-deleted, .CodeMirror-merge-l-deleted { | |
| 81 | + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12M4Kyb2/6yY2H8GBgYGJgYkAABURgPz6Ks7wQAAAABJRU5ErkJggg==); | |
| 82 | + background-position: bottom left; | |
| 83 | + background-repeat: repeat-x; | |
| 84 | +} | |
| 85 | + | |
| 86 | +.CodeMirror-merge-r-chunk { background: #ffffe0; } | |
| 87 | +.CodeMirror-merge-r-chunk-start { border-top: 1px solid #ee8; } | |
| 88 | +.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #ee8; } | |
| 89 | +.CodeMirror-merge-r-connect { fill: #ffffe0; stroke: #ee8; stroke-width: 1px; } | |
| 90 | + | |
| 91 | +.CodeMirror-merge-l-chunk { background: #eef; } | |
| 92 | +.CodeMirror-merge-l-chunk-start { border-top: 1px solid #88e; } | |
| 93 | +.CodeMirror-merge-l-chunk-end { border-bottom: 1px solid #88e; } | |
| 94 | +.CodeMirror-merge-l-connect { fill: #eef; stroke: #88e; stroke-width: 1px; } | |
| 95 | + | |
| 96 | +.CodeMirror-merge-l-chunk.CodeMirror-merge-r-chunk { background: #dfd; } | |
| 97 | +.CodeMirror-merge-l-chunk-start.CodeMirror-merge-r-chunk-start { border-top: 1px solid #4e4; } | |
| 98 | +.CodeMirror-merge-l-chunk-end.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #4e4; } | ... | ... |
| ... | ... | @@ -0,0 +1,536 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +// declare global: diff_match_patch, DIFF_INSERT, DIFF_DELETE, DIFF_EQUAL | |
| 5 | + | |
| 6 | +(function(mod) { | |
| 7 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 8 | + mod(require("../../lib/codemirror"), require("diff_match_patch")); | |
| 9 | + else if (typeof define == "function" && define.amd) // AMD | |
| 10 | + define(["../../lib/codemirror", "diff_match_patch"], mod); | |
| 11 | + else // Plain browser env | |
| 12 | + mod(CodeMirror, diff_match_patch); | |
| 13 | +})(function(CodeMirror, diff_match_patch) { | |
| 14 | + "use strict"; | |
| 15 | + var Pos = CodeMirror.Pos; | |
| 16 | + var svgNS = "http://www.w3.org/2000/svg"; | |
| 17 | + | |
| 18 | + function DiffView(mv, type) { | |
| 19 | + this.mv = mv; | |
| 20 | + this.type = type; | |
| 21 | + this.classes = type == "left" | |
| 22 | + ? {chunk: "CodeMirror-merge-l-chunk", | |
| 23 | + start: "CodeMirror-merge-l-chunk-start", | |
| 24 | + end: "CodeMirror-merge-l-chunk-end", | |
| 25 | + insert: "CodeMirror-merge-l-inserted", | |
| 26 | + del: "CodeMirror-merge-l-deleted", | |
| 27 | + connect: "CodeMirror-merge-l-connect"} | |
| 28 | + : {chunk: "CodeMirror-merge-r-chunk", | |
| 29 | + start: "CodeMirror-merge-r-chunk-start", | |
| 30 | + end: "CodeMirror-merge-r-chunk-end", | |
| 31 | + insert: "CodeMirror-merge-r-inserted", | |
| 32 | + del: "CodeMirror-merge-r-deleted", | |
| 33 | + connect: "CodeMirror-merge-r-connect"}; | |
| 34 | + } | |
| 35 | + | |
| 36 | + DiffView.prototype = { | |
| 37 | + constructor: DiffView, | |
| 38 | + init: function(pane, orig, options) { | |
| 39 | + this.edit = this.mv.edit; | |
| 40 | + this.orig = CodeMirror(pane, copyObj({value: orig, readOnly: !this.mv.options.allowEditingOriginals}, copyObj(options))); | |
| 41 | + | |
| 42 | + this.diff = getDiff(asString(orig), asString(options.value)); | |
| 43 | + this.diffOutOfDate = false; | |
| 44 | + | |
| 45 | + this.showDifferences = options.showDifferences !== false; | |
| 46 | + this.forceUpdate = registerUpdate(this); | |
| 47 | + setScrollLock(this, true, false); | |
| 48 | + registerScroll(this); | |
| 49 | + }, | |
| 50 | + setShowDifferences: function(val) { | |
| 51 | + val = val !== false; | |
| 52 | + if (val != this.showDifferences) { | |
| 53 | + this.showDifferences = val; | |
| 54 | + this.forceUpdate("full"); | |
| 55 | + } | |
| 56 | + } | |
| 57 | + }; | |
| 58 | + | |
| 59 | + function ensureDiff(dv) { | |
| 60 | + if (dv.diffOutOfDate) { | |
| 61 | + dv.diff = getDiff(dv.orig.getValue(), dv.edit.getValue()); | |
| 62 | + dv.diffOutOfDate = false; | |
| 63 | + CodeMirror.signal(dv.edit, "updateDiff", dv.diff); | |
| 64 | + } | |
| 65 | + } | |
| 66 | + | |
| 67 | + function registerUpdate(dv) { | |
| 68 | + var edit = {from: 0, to: 0, marked: []}; | |
| 69 | + var orig = {from: 0, to: 0, marked: []}; | |
| 70 | + var debounceChange; | |
| 71 | + function update(mode) { | |
| 72 | + if (mode == "full") { | |
| 73 | + if (dv.svg) clear(dv.svg); | |
| 74 | + if (dv.copyButtons) clear(dv.copyButtons); | |
| 75 | + clearMarks(dv.edit, edit.marked, dv.classes); | |
| 76 | + clearMarks(dv.orig, orig.marked, dv.classes); | |
| 77 | + edit.from = edit.to = orig.from = orig.to = 0; | |
| 78 | + } | |
| 79 | + ensureDiff(dv); | |
| 80 | + if (dv.showDifferences) { | |
| 81 | + updateMarks(dv.edit, dv.diff, edit, DIFF_INSERT, dv.classes); | |
| 82 | + updateMarks(dv.orig, dv.diff, orig, DIFF_DELETE, dv.classes); | |
| 83 | + } | |
| 84 | + drawConnectors(dv); | |
| 85 | + } | |
| 86 | + function set(slow) { | |
| 87 | + clearTimeout(debounceChange); | |
| 88 | + debounceChange = setTimeout(update, slow == true ? 250 : 100); | |
| 89 | + } | |
| 90 | + function change() { | |
| 91 | + if (!dv.diffOutOfDate) { | |
| 92 | + dv.diffOutOfDate = true; | |
| 93 | + edit.from = edit.to = orig.from = orig.to = 0; | |
| 94 | + } | |
| 95 | + set(true); | |
| 96 | + } | |
| 97 | + dv.edit.on("change", change); | |
| 98 | + dv.orig.on("change", change); | |
| 99 | + dv.edit.on("markerAdded", set); | |
| 100 | + dv.edit.on("markerCleared", set); | |
| 101 | + dv.orig.on("markerAdded", set); | |
| 102 | + dv.orig.on("markerCleared", set); | |
| 103 | + dv.edit.on("viewportChange", set); | |
| 104 | + dv.orig.on("viewportChange", set); | |
| 105 | + update(); | |
| 106 | + return update; | |
| 107 | + } | |
| 108 | + | |
| 109 | + function registerScroll(dv) { | |
| 110 | + dv.edit.on("scroll", function() { | |
| 111 | + syncScroll(dv, DIFF_INSERT) && drawConnectors(dv); | |
| 112 | + }); | |
| 113 | + dv.orig.on("scroll", function() { | |
| 114 | + syncScroll(dv, DIFF_DELETE) && drawConnectors(dv); | |
| 115 | + }); | |
| 116 | + } | |
| 117 | + | |
| 118 | + function syncScroll(dv, type) { | |
| 119 | + // Change handler will do a refresh after a timeout when diff is out of date | |
| 120 | + if (dv.diffOutOfDate) return false; | |
| 121 | + if (!dv.lockScroll) return true; | |
| 122 | + var editor, other, now = +new Date; | |
| 123 | + if (type == DIFF_INSERT) { editor = dv.edit; other = dv.orig; } | |
| 124 | + else { editor = dv.orig; other = dv.edit; } | |
| 125 | + // Don't take action if the position of this editor was recently set | |
| 126 | + // (to prevent feedback loops) | |
| 127 | + if (editor.state.scrollSetBy == dv && (editor.state.scrollSetAt || 0) + 50 > now) return false; | |
| 128 | + | |
| 129 | + var sInfo = editor.getScrollInfo(), halfScreen = .5 * sInfo.clientHeight, midY = sInfo.top + halfScreen; | |
| 130 | + var mid = editor.lineAtHeight(midY, "local"); | |
| 131 | + var around = chunkBoundariesAround(dv.diff, mid, type == DIFF_INSERT); | |
| 132 | + var off = getOffsets(editor, type == DIFF_INSERT ? around.edit : around.orig); | |
| 133 | + var offOther = getOffsets(other, type == DIFF_INSERT ? around.orig : around.edit); | |
| 134 | + var ratio = (midY - off.top) / (off.bot - off.top); | |
| 135 | + var targetPos = (offOther.top - halfScreen) + ratio * (offOther.bot - offOther.top); | |
| 136 | + | |
| 137 | + var botDist, mix; | |
| 138 | + // Some careful tweaking to make sure no space is left out of view | |
| 139 | + // when scrolling to top or bottom. | |
| 140 | + if (targetPos > sInfo.top && (mix = sInfo.top / halfScreen) < 1) { | |
| 141 | + targetPos = targetPos * mix + sInfo.top * (1 - mix); | |
| 142 | + } else if ((botDist = sInfo.height - sInfo.clientHeight - sInfo.top) < halfScreen) { | |
| 143 | + var otherInfo = other.getScrollInfo(); | |
| 144 | + var botDistOther = otherInfo.height - otherInfo.clientHeight - targetPos; | |
| 145 | + if (botDistOther > botDist && (mix = botDist / halfScreen) < 1) | |
| 146 | + targetPos = targetPos * mix + (otherInfo.height - otherInfo.clientHeight - botDist) * (1 - mix); | |
| 147 | + } | |
| 148 | + | |
| 149 | + other.scrollTo(sInfo.left, targetPos); | |
| 150 | + other.state.scrollSetAt = now; | |
| 151 | + other.state.scrollSetBy = dv; | |
| 152 | + return true; | |
| 153 | + } | |
| 154 | + | |
| 155 | + function getOffsets(editor, around) { | |
| 156 | + var bot = around.after; | |
| 157 | + if (bot == null) bot = editor.lastLine() + 1; | |
| 158 | + return {top: editor.heightAtLine(around.before || 0, "local"), | |
| 159 | + bot: editor.heightAtLine(bot, "local")}; | |
| 160 | + } | |
| 161 | + | |
| 162 | + function setScrollLock(dv, val, action) { | |
| 163 | + dv.lockScroll = val; | |
| 164 | + if (val && action != false) syncScroll(dv, DIFF_INSERT) && drawConnectors(dv); | |
| 165 | + dv.lockButton.innerHTML = val ? "\u21db\u21da" : "\u21db \u21da"; | |
| 166 | + } | |
| 167 | + | |
| 168 | + // Updating the marks for editor content | |
| 169 | + | |
| 170 | + function clearMarks(editor, arr, classes) { | |
| 171 | + for (var i = 0; i < arr.length; ++i) { | |
| 172 | + var mark = arr[i]; | |
| 173 | + if (mark instanceof CodeMirror.TextMarker) { | |
| 174 | + mark.clear(); | |
| 175 | + } else if (mark.parent) { | |
| 176 | + editor.removeLineClass(mark, "background", classes.chunk); | |
| 177 | + editor.removeLineClass(mark, "background", classes.start); | |
| 178 | + editor.removeLineClass(mark, "background", classes.end); | |
| 179 | + } | |
| 180 | + } | |
| 181 | + arr.length = 0; | |
| 182 | + } | |
| 183 | + | |
| 184 | + // FIXME maybe add a margin around viewport to prevent too many updates | |
| 185 | + function updateMarks(editor, diff, state, type, classes) { | |
| 186 | + var vp = editor.getViewport(); | |
| 187 | + editor.operation(function() { | |
| 188 | + if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) { | |
| 189 | + clearMarks(editor, state.marked, classes); | |
| 190 | + markChanges(editor, diff, type, state.marked, vp.from, vp.to, classes); | |
| 191 | + state.from = vp.from; state.to = vp.to; | |
| 192 | + } else { | |
| 193 | + if (vp.from < state.from) { | |
| 194 | + markChanges(editor, diff, type, state.marked, vp.from, state.from, classes); | |
| 195 | + state.from = vp.from; | |
| 196 | + } | |
| 197 | + if (vp.to > state.to) { | |
| 198 | + markChanges(editor, diff, type, state.marked, state.to, vp.to, classes); | |
| 199 | + state.to = vp.to; | |
| 200 | + } | |
| 201 | + } | |
| 202 | + }); | |
| 203 | + } | |
| 204 | + | |
| 205 | + function markChanges(editor, diff, type, marks, from, to, classes) { | |
| 206 | + var pos = Pos(0, 0); | |
| 207 | + var top = Pos(from, 0), bot = editor.clipPos(Pos(to - 1)); | |
| 208 | + var cls = type == DIFF_DELETE ? classes.del : classes.insert; | |
| 209 | + function markChunk(start, end) { | |
| 210 | + var bfrom = Math.max(from, start), bto = Math.min(to, end); | |
| 211 | + for (var i = bfrom; i < bto; ++i) { | |
| 212 | + var line = editor.addLineClass(i, "background", classes.chunk); | |
| 213 | + if (i == start) editor.addLineClass(line, "background", classes.start); | |
| 214 | + if (i == end - 1) editor.addLineClass(line, "background", classes.end); | |
| 215 | + marks.push(line); | |
| 216 | + } | |
| 217 | + // When the chunk is empty, make sure a horizontal line shows up | |
| 218 | + if (start == end && bfrom == end && bto == end) { | |
| 219 | + if (bfrom) | |
| 220 | + marks.push(editor.addLineClass(bfrom - 1, "background", classes.end)); | |
| 221 | + else | |
| 222 | + marks.push(editor.addLineClass(bfrom, "background", classes.start)); | |
| 223 | + } | |
| 224 | + } | |
| 225 | + | |
| 226 | + var chunkStart = 0; | |
| 227 | + for (var i = 0; i < diff.length; ++i) { | |
| 228 | + var part = diff[i], tp = part[0], str = part[1]; | |
| 229 | + if (tp == DIFF_EQUAL) { | |
| 230 | + var cleanFrom = pos.line + (startOfLineClean(diff, i) ? 0 : 1); | |
| 231 | + moveOver(pos, str); | |
| 232 | + var cleanTo = pos.line + (endOfLineClean(diff, i) ? 1 : 0); | |
| 233 | + if (cleanTo > cleanFrom) { | |
| 234 | + if (i) markChunk(chunkStart, cleanFrom); | |
| 235 | + chunkStart = cleanTo; | |
| 236 | + } | |
| 237 | + } else { | |
| 238 | + if (tp == type) { | |
| 239 | + var end = moveOver(pos, str, true); | |
| 240 | + var a = posMax(top, pos), b = posMin(bot, end); | |
| 241 | + if (!posEq(a, b)) | |
| 242 | + marks.push(editor.markText(a, b, {className: cls})); | |
| 243 | + pos = end; | |
| 244 | + } | |
| 245 | + } | |
| 246 | + } | |
| 247 | + if (chunkStart <= pos.line) markChunk(chunkStart, pos.line + 1); | |
| 248 | + } | |
| 249 | + | |
| 250 | + // Updating the gap between editor and original | |
| 251 | + | |
| 252 | + function drawConnectors(dv) { | |
| 253 | + if (!dv.showDifferences) return; | |
| 254 | + | |
| 255 | + if (dv.svg) { | |
| 256 | + clear(dv.svg); | |
| 257 | + var w = dv.gap.offsetWidth; | |
| 258 | + attrs(dv.svg, "width", w, "height", dv.gap.offsetHeight); | |
| 259 | + } | |
| 260 | + if (dv.copyButtons) clear(dv.copyButtons); | |
| 261 | + | |
| 262 | + var flip = dv.type == "left"; | |
| 263 | + var vpEdit = dv.edit.getViewport(), vpOrig = dv.orig.getViewport(); | |
| 264 | + var sTopEdit = dv.edit.getScrollInfo().top, sTopOrig = dv.orig.getScrollInfo().top; | |
| 265 | + iterateChunks(dv.diff, function(topOrig, botOrig, topEdit, botEdit) { | |
| 266 | + if (topEdit > vpEdit.to || botEdit < vpEdit.from || | |
| 267 | + topOrig > vpOrig.to || botOrig < vpOrig.from) | |
| 268 | + return; | |
| 269 | + var topLpx = dv.orig.heightAtLine(topOrig, "local") - sTopOrig, top = topLpx; | |
| 270 | + if (dv.svg) { | |
| 271 | + var topRpx = dv.edit.heightAtLine(topEdit, "local") - sTopEdit; | |
| 272 | + if (flip) { var tmp = topLpx; topLpx = topRpx; topRpx = tmp; } | |
| 273 | + var botLpx = dv.orig.heightAtLine(botOrig, "local") - sTopOrig; | |
| 274 | + var botRpx = dv.edit.heightAtLine(botEdit, "local") - sTopEdit; | |
| 275 | + if (flip) { var tmp = botLpx; botLpx = botRpx; botRpx = tmp; } | |
| 276 | + var curveTop = " C " + w/2 + " " + topRpx + " " + w/2 + " " + topLpx + " " + (w + 2) + " " + topLpx; | |
| 277 | + var curveBot = " C " + w/2 + " " + botLpx + " " + w/2 + " " + botRpx + " -1 " + botRpx; | |
| 278 | + attrs(dv.svg.appendChild(document.createElementNS(svgNS, "path")), | |
| 279 | + "d", "M -1 " + topRpx + curveTop + " L " + (w + 2) + " " + botLpx + curveBot + " z", | |
| 280 | + "class", dv.classes.connect); | |
| 281 | + } | |
| 282 | + if (dv.copyButtons) { | |
| 283 | + var copy = dv.copyButtons.appendChild(elt("div", dv.type == "left" ? "\u21dd" : "\u21dc", | |
| 284 | + "CodeMirror-merge-copy")); | |
| 285 | + var editOriginals = dv.mv.options.allowEditingOriginals; | |
| 286 | + copy.title = editOriginals ? "Push to left" : "Revert chunk"; | |
| 287 | + copy.chunk = {topEdit: topEdit, botEdit: botEdit, topOrig: topOrig, botOrig: botOrig}; | |
| 288 | + copy.style.top = top + "px"; | |
| 289 | + | |
| 290 | + if (editOriginals) { | |
| 291 | + var topReverse = dv.orig.heightAtLine(topEdit, "local") - sTopEdit; | |
| 292 | + var copyReverse = dv.copyButtons.appendChild(elt("div", dv.type == "right" ? "\u21dd" : "\u21dc", | |
| 293 | + "CodeMirror-merge-copy-reverse")); | |
| 294 | + copyReverse.title = "Push to right"; | |
| 295 | + copyReverse.chunk = {topEdit: topOrig, botEdit: botOrig, topOrig: topEdit, botOrig: botEdit}; | |
| 296 | + copyReverse.style.top = topReverse + "px"; | |
| 297 | + dv.type == "right" ? copyReverse.style.left = "2px" : copyReverse.style.right = "2px"; | |
| 298 | + } | |
| 299 | + } | |
| 300 | + }); | |
| 301 | + } | |
| 302 | + | |
| 303 | + function copyChunk(dv, to, from, chunk) { | |
| 304 | + if (dv.diffOutOfDate) return; | |
| 305 | + to.replaceRange(from.getRange(Pos(chunk.topOrig, 0), Pos(chunk.botOrig, 0)), | |
| 306 | + Pos(chunk.topEdit, 0), Pos(chunk.botEdit, 0)); | |
| 307 | + } | |
| 308 | + | |
| 309 | + // Merge view, containing 0, 1, or 2 diff views. | |
| 310 | + | |
| 311 | + var MergeView = CodeMirror.MergeView = function(node, options) { | |
| 312 | + if (!(this instanceof MergeView)) return new MergeView(node, options); | |
| 313 | + | |
| 314 | + this.options = options; | |
| 315 | + var origLeft = options.origLeft, origRight = options.origRight == null ? options.orig : options.origRight; | |
| 316 | + var hasLeft = origLeft != null, hasRight = origRight != null; | |
| 317 | + var panes = 1 + (hasLeft ? 1 : 0) + (hasRight ? 1 : 0); | |
| 318 | + var wrap = [], left = this.left = null, right = this.right = null; | |
| 319 | + | |
| 320 | + if (hasLeft) { | |
| 321 | + left = this.left = new DiffView(this, "left"); | |
| 322 | + var leftPane = elt("div", null, "CodeMirror-merge-pane"); | |
| 323 | + wrap.push(leftPane); | |
| 324 | + wrap.push(buildGap(left)); | |
| 325 | + } | |
| 326 | + | |
| 327 | + var editPane = elt("div", null, "CodeMirror-merge-pane"); | |
| 328 | + wrap.push(editPane); | |
| 329 | + | |
| 330 | + if (hasRight) { | |
| 331 | + right = this.right = new DiffView(this, "right"); | |
| 332 | + wrap.push(buildGap(right)); | |
| 333 | + var rightPane = elt("div", null, "CodeMirror-merge-pane"); | |
| 334 | + wrap.push(rightPane); | |
| 335 | + } | |
| 336 | + | |
| 337 | + (hasRight ? rightPane : editPane).className += " CodeMirror-merge-pane-rightmost"; | |
| 338 | + | |
| 339 | + wrap.push(elt("div", null, null, "height: 0; clear: both;")); | |
| 340 | + | |
| 341 | + var wrapElt = this.wrap = node.appendChild(elt("div", wrap, "CodeMirror-merge CodeMirror-merge-" + panes + "pane")); | |
| 342 | + this.edit = CodeMirror(editPane, copyObj(options)); | |
| 343 | + | |
| 344 | + if (left) left.init(leftPane, origLeft, options); | |
| 345 | + if (right) right.init(rightPane, origRight, options); | |
| 346 | + | |
| 347 | + var onResize = function() { | |
| 348 | + if (left) drawConnectors(left); | |
| 349 | + if (right) drawConnectors(right); | |
| 350 | + }; | |
| 351 | + CodeMirror.on(window, "resize", onResize); | |
| 352 | + var resizeInterval = setInterval(function() { | |
| 353 | + for (var p = wrapElt.parentNode; p && p != document.body; p = p.parentNode) {} | |
| 354 | + if (!p) { clearInterval(resizeInterval); CodeMirror.off(window, "resize", onResize); } | |
| 355 | + }, 5000); | |
| 356 | + }; | |
| 357 | + | |
| 358 | + function buildGap(dv) { | |
| 359 | + var lock = dv.lockButton = elt("div", null, "CodeMirror-merge-scrolllock"); | |
| 360 | + lock.title = "Toggle locked scrolling"; | |
| 361 | + var lockWrap = elt("div", [lock], "CodeMirror-merge-scrolllock-wrap"); | |
| 362 | + CodeMirror.on(lock, "click", function() { setScrollLock(dv, !dv.lockScroll); }); | |
| 363 | + var gapElts = [lockWrap]; | |
| 364 | + if (dv.mv.options.revertButtons !== false) { | |
| 365 | + dv.copyButtons = elt("div", null, "CodeMirror-merge-copybuttons-" + dv.type); | |
| 366 | + CodeMirror.on(dv.copyButtons, "click", function(e) { | |
| 367 | + var node = e.target || e.srcElement; | |
| 368 | + if (!node.chunk) return; | |
| 369 | + if (node.className == "CodeMirror-merge-copy-reverse") { | |
| 370 | + copyChunk(dv, dv.orig, dv.edit, node.chunk); | |
| 371 | + return; | |
| 372 | + } | |
| 373 | + copyChunk(dv, dv.edit, dv.orig, node.chunk); | |
| 374 | + }); | |
| 375 | + gapElts.unshift(dv.copyButtons); | |
| 376 | + } | |
| 377 | + var svg = document.createElementNS && document.createElementNS(svgNS, "svg"); | |
| 378 | + if (svg && !svg.createSVGRect) svg = null; | |
| 379 | + dv.svg = svg; | |
| 380 | + if (svg) gapElts.push(svg); | |
| 381 | + | |
| 382 | + return dv.gap = elt("div", gapElts, "CodeMirror-merge-gap"); | |
| 383 | + } | |
| 384 | + | |
| 385 | + MergeView.prototype = { | |
| 386 | + constuctor: MergeView, | |
| 387 | + editor: function() { return this.edit; }, | |
| 388 | + rightOriginal: function() { return this.right && this.right.orig; }, | |
| 389 | + leftOriginal: function() { return this.left && this.left.orig; }, | |
| 390 | + setShowDifferences: function(val) { | |
| 391 | + if (this.right) this.right.setShowDifferences(val); | |
| 392 | + if (this.left) this.left.setShowDifferences(val); | |
| 393 | + }, | |
| 394 | + rightChunks: function() { | |
| 395 | + return this.right && getChunks(this.right); | |
| 396 | + }, | |
| 397 | + leftChunks: function() { | |
| 398 | + return this.left && getChunks(this.left); | |
| 399 | + } | |
| 400 | + }; | |
| 401 | + | |
| 402 | + function asString(obj) { | |
| 403 | + if (typeof obj == "string") return obj; | |
| 404 | + else return obj.getValue(); | |
| 405 | + } | |
| 406 | + | |
| 407 | + // Operations on diffs | |
| 408 | + | |
| 409 | + var dmp = new diff_match_patch(); | |
| 410 | + function getDiff(a, b) { | |
| 411 | + var diff = dmp.diff_main(a, b); | |
| 412 | + dmp.diff_cleanupSemantic(diff); | |
| 413 | + // The library sometimes leaves in empty parts, which confuse the algorithm | |
| 414 | + for (var i = 0; i < diff.length; ++i) { | |
| 415 | + var part = diff[i]; | |
| 416 | + if (!part[1]) { | |
| 417 | + diff.splice(i--, 1); | |
| 418 | + } else if (i && diff[i - 1][0] == part[0]) { | |
| 419 | + diff.splice(i--, 1); | |
| 420 | + diff[i][1] += part[1]; | |
| 421 | + } | |
| 422 | + } | |
| 423 | + return diff; | |
| 424 | + } | |
| 425 | + | |
| 426 | + function iterateChunks(diff, f) { | |
| 427 | + var startEdit = 0, startOrig = 0; | |
| 428 | + var edit = Pos(0, 0), orig = Pos(0, 0); | |
| 429 | + for (var i = 0; i < diff.length; ++i) { | |
| 430 | + var part = diff[i], tp = part[0]; | |
| 431 | + if (tp == DIFF_EQUAL) { | |
| 432 | + var startOff = startOfLineClean(diff, i) ? 0 : 1; | |
| 433 | + var cleanFromEdit = edit.line + startOff, cleanFromOrig = orig.line + startOff; | |
| 434 | + moveOver(edit, part[1], null, orig); | |
| 435 | + var endOff = endOfLineClean(diff, i) ? 1 : 0; | |
| 436 | + var cleanToEdit = edit.line + endOff, cleanToOrig = orig.line + endOff; | |
| 437 | + if (cleanToEdit > cleanFromEdit) { | |
| 438 | + if (i) f(startOrig, cleanFromOrig, startEdit, cleanFromEdit); | |
| 439 | + startEdit = cleanToEdit; startOrig = cleanToOrig; | |
| 440 | + } | |
| 441 | + } else { | |
| 442 | + moveOver(tp == DIFF_INSERT ? edit : orig, part[1]); | |
| 443 | + } | |
| 444 | + } | |
| 445 | + if (startEdit <= edit.line || startOrig <= orig.line) | |
| 446 | + f(startOrig, orig.line + 1, startEdit, edit.line + 1); | |
| 447 | + } | |
| 448 | + | |
| 449 | + function getChunks(dv) { | |
| 450 | + ensureDiff(dv); | |
| 451 | + var collect = []; | |
| 452 | + iterateChunks(dv.diff, function(topOrig, botOrig, topEdit, botEdit) { | |
| 453 | + collect.push({origFrom: topOrig, origTo: botOrig, | |
| 454 | + editFrom: topEdit, editTo: botEdit}); | |
| 455 | + }); | |
| 456 | + return collect; | |
| 457 | + } | |
| 458 | + | |
| 459 | + function endOfLineClean(diff, i) { | |
| 460 | + if (i == diff.length - 1) return true; | |
| 461 | + var next = diff[i + 1][1]; | |
| 462 | + if (next.length == 1 || next.charCodeAt(0) != 10) return false; | |
| 463 | + if (i == diff.length - 2) return true; | |
| 464 | + next = diff[i + 2][1]; | |
| 465 | + return next.length > 1 && next.charCodeAt(0) == 10; | |
| 466 | + } | |
| 467 | + | |
| 468 | + function startOfLineClean(diff, i) { | |
| 469 | + if (i == 0) return true; | |
| 470 | + var last = diff[i - 1][1]; | |
| 471 | + if (last.charCodeAt(last.length - 1) != 10) return false; | |
| 472 | + if (i == 1) return true; | |
| 473 | + last = diff[i - 2][1]; | |
| 474 | + return last.charCodeAt(last.length - 1) == 10; | |
| 475 | + } | |
| 476 | + | |
| 477 | + function chunkBoundariesAround(diff, n, nInEdit) { | |
| 478 | + var beforeE, afterE, beforeO, afterO; | |
| 479 | + iterateChunks(diff, function(fromOrig, toOrig, fromEdit, toEdit) { | |
| 480 | + var fromLocal = nInEdit ? fromEdit : fromOrig; | |
| 481 | + var toLocal = nInEdit ? toEdit : toOrig; | |
| 482 | + if (afterE == null) { | |
| 483 | + if (fromLocal > n) { afterE = fromEdit; afterO = fromOrig; } | |
| 484 | + else if (toLocal > n) { afterE = toEdit; afterO = toOrig; } | |
| 485 | + } | |
| 486 | + if (toLocal <= n) { beforeE = toEdit; beforeO = toOrig; } | |
| 487 | + else if (fromLocal <= n) { beforeE = fromEdit; beforeO = fromOrig; } | |
| 488 | + }); | |
| 489 | + return {edit: {before: beforeE, after: afterE}, orig: {before: beforeO, after: afterO}}; | |
| 490 | + } | |
| 491 | + | |
| 492 | + // General utilities | |
| 493 | + | |
| 494 | + function elt(tag, content, className, style) { | |
| 495 | + var e = document.createElement(tag); | |
| 496 | + if (className) e.className = className; | |
| 497 | + if (style) e.style.cssText = style; | |
| 498 | + if (typeof content == "string") e.appendChild(document.createTextNode(content)); | |
| 499 | + else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]); | |
| 500 | + return e; | |
| 501 | + } | |
| 502 | + | |
| 503 | + function clear(node) { | |
| 504 | + for (var count = node.childNodes.length; count > 0; --count) | |
| 505 | + node.removeChild(node.firstChild); | |
| 506 | + } | |
| 507 | + | |
| 508 | + function attrs(elt) { | |
| 509 | + for (var i = 1; i < arguments.length; i += 2) | |
| 510 | + elt.setAttribute(arguments[i], arguments[i+1]); | |
| 511 | + } | |
| 512 | + | |
| 513 | + function copyObj(obj, target) { | |
| 514 | + if (!target) target = {}; | |
| 515 | + for (var prop in obj) if (obj.hasOwnProperty(prop)) target[prop] = obj[prop]; | |
| 516 | + return target; | |
| 517 | + } | |
| 518 | + | |
| 519 | + function moveOver(pos, str, copy, other) { | |
| 520 | + var out = copy ? Pos(pos.line, pos.ch) : pos, at = 0; | |
| 521 | + for (;;) { | |
| 522 | + var nl = str.indexOf("\n", at); | |
| 523 | + if (nl == -1) break; | |
| 524 | + ++out.line; | |
| 525 | + if (other) ++other.line; | |
| 526 | + at = nl + 1; | |
| 527 | + } | |
| 528 | + out.ch = (at ? 0 : out.ch) + (str.length - at); | |
| 529 | + if (other) other.ch = (at ? 0 : other.ch) + (str.length - at); | |
| 530 | + return out; | |
| 531 | + } | |
| 532 | + | |
| 533 | + function posMin(a, b) { return (a.line - b.line || a.ch - b.ch) < 0 ? a : b; } | |
| 534 | + function posMax(a, b) { return (a.line - b.line || a.ch - b.ch) > 0 ? a : b; } | |
| 535 | + function posEq(a, b) { return a.line == b.line && a.ch == b.ch; } | |
| 536 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,61 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + if (!CodeMirror.modeURL) CodeMirror.modeURL = "../mode/%N/%N.js"; | |
| 13 | + | |
| 14 | + var loading = {}; | |
| 15 | + function splitCallback(cont, n) { | |
| 16 | + var countDown = n; | |
| 17 | + return function() { if (--countDown == 0) cont(); }; | |
| 18 | + } | |
| 19 | + function ensureDeps(mode, cont) { | |
| 20 | + var deps = CodeMirror.modes[mode].dependencies; | |
| 21 | + if (!deps) return cont(); | |
| 22 | + var missing = []; | |
| 23 | + for (var i = 0; i < deps.length; ++i) { | |
| 24 | + if (!CodeMirror.modes.hasOwnProperty(deps[i])) | |
| 25 | + missing.push(deps[i]); | |
| 26 | + } | |
| 27 | + if (!missing.length) return cont(); | |
| 28 | + var split = splitCallback(cont, missing.length); | |
| 29 | + for (var i = 0; i < missing.length; ++i) | |
| 30 | + CodeMirror.requireMode(missing[i], split); | |
| 31 | + } | |
| 32 | + | |
| 33 | + CodeMirror.requireMode = function(mode, cont) { | |
| 34 | + if (typeof mode != "string") mode = mode.name; | |
| 35 | + if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont); | |
| 36 | + if (loading.hasOwnProperty(mode)) return loading[mode].push(cont); | |
| 37 | + | |
| 38 | + var script = document.createElement("script"); | |
| 39 | + script.src = CodeMirror.modeURL.replace(/%N/g, mode); | |
| 40 | + var others = document.getElementsByTagName("script")[0]; | |
| 41 | + others.parentNode.insertBefore(script, others); | |
| 42 | + var list = loading[mode] = [cont]; | |
| 43 | + var count = 0, poll = setInterval(function() { | |
| 44 | + if (++count > 100) return clearInterval(poll); | |
| 45 | + if (CodeMirror.modes.hasOwnProperty(mode)) { | |
| 46 | + clearInterval(poll); | |
| 47 | + loading[mode] = null; | |
| 48 | + ensureDeps(mode, function() { | |
| 49 | + for (var i = 0; i < list.length; ++i) list[i](); | |
| 50 | + }); | |
| 51 | + } | |
| 52 | + }, 200); | |
| 53 | + }; | |
| 54 | + | |
| 55 | + CodeMirror.autoLoadMode = function(instance, mode) { | |
| 56 | + if (!CodeMirror.modes.hasOwnProperty(mode)) | |
| 57 | + CodeMirror.requireMode(mode, function() { | |
| 58 | + instance.setOption("mode", instance.getOption("mode")); | |
| 59 | + }); | |
| 60 | + }; | |
| 61 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,118 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | +"use strict"; | |
| 13 | + | |
| 14 | +CodeMirror.multiplexingMode = function(outer /*, others */) { | |
| 15 | + // Others should be {open, close, mode [, delimStyle] [, innerStyle]} objects | |
| 16 | + var others = Array.prototype.slice.call(arguments, 1); | |
| 17 | + var n_others = others.length; | |
| 18 | + | |
| 19 | + function indexOf(string, pattern, from) { | |
| 20 | + if (typeof pattern == "string") return string.indexOf(pattern, from); | |
| 21 | + var m = pattern.exec(from ? string.slice(from) : string); | |
| 22 | + return m ? m.index + from : -1; | |
| 23 | + } | |
| 24 | + | |
| 25 | + return { | |
| 26 | + startState: function() { | |
| 27 | + return { | |
| 28 | + outer: CodeMirror.startState(outer), | |
| 29 | + innerActive: null, | |
| 30 | + inner: null | |
| 31 | + }; | |
| 32 | + }, | |
| 33 | + | |
| 34 | + copyState: function(state) { | |
| 35 | + return { | |
| 36 | + outer: CodeMirror.copyState(outer, state.outer), | |
| 37 | + innerActive: state.innerActive, | |
| 38 | + inner: state.innerActive && CodeMirror.copyState(state.innerActive.mode, state.inner) | |
| 39 | + }; | |
| 40 | + }, | |
| 41 | + | |
| 42 | + token: function(stream, state) { | |
| 43 | + if (!state.innerActive) { | |
| 44 | + var cutOff = Infinity, oldContent = stream.string; | |
| 45 | + for (var i = 0; i < n_others; ++i) { | |
| 46 | + var other = others[i]; | |
| 47 | + var found = indexOf(oldContent, other.open, stream.pos); | |
| 48 | + if (found == stream.pos) { | |
| 49 | + stream.match(other.open); | |
| 50 | + state.innerActive = other; | |
| 51 | + state.inner = CodeMirror.startState(other.mode, outer.indent ? outer.indent(state.outer, "") : 0); | |
| 52 | + return other.delimStyle; | |
| 53 | + } else if (found != -1 && found < cutOff) { | |
| 54 | + cutOff = found; | |
| 55 | + } | |
| 56 | + } | |
| 57 | + if (cutOff != Infinity) stream.string = oldContent.slice(0, cutOff); | |
| 58 | + var outerToken = outer.token(stream, state.outer); | |
| 59 | + if (cutOff != Infinity) stream.string = oldContent; | |
| 60 | + return outerToken; | |
| 61 | + } else { | |
| 62 | + var curInner = state.innerActive, oldContent = stream.string; | |
| 63 | + if (!curInner.close && stream.sol()) { | |
| 64 | + state.innerActive = state.inner = null; | |
| 65 | + return this.token(stream, state); | |
| 66 | + } | |
| 67 | + var found = curInner.close ? indexOf(oldContent, curInner.close, stream.pos) : -1; | |
| 68 | + if (found == stream.pos) { | |
| 69 | + stream.match(curInner.close); | |
| 70 | + state.innerActive = state.inner = null; | |
| 71 | + return curInner.delimStyle; | |
| 72 | + } | |
| 73 | + if (found > -1) stream.string = oldContent.slice(0, found); | |
| 74 | + var innerToken = curInner.mode.token(stream, state.inner); | |
| 75 | + if (found > -1) stream.string = oldContent; | |
| 76 | + | |
| 77 | + if (curInner.innerStyle) { | |
| 78 | + if (innerToken) innerToken = innerToken + ' ' + curInner.innerStyle; | |
| 79 | + else innerToken = curInner.innerStyle; | |
| 80 | + } | |
| 81 | + | |
| 82 | + return innerToken; | |
| 83 | + } | |
| 84 | + }, | |
| 85 | + | |
| 86 | + indent: function(state, textAfter) { | |
| 87 | + var mode = state.innerActive ? state.innerActive.mode : outer; | |
| 88 | + if (!mode.indent) return CodeMirror.Pass; | |
| 89 | + return mode.indent(state.innerActive ? state.inner : state.outer, textAfter); | |
| 90 | + }, | |
| 91 | + | |
| 92 | + blankLine: function(state) { | |
| 93 | + var mode = state.innerActive ? state.innerActive.mode : outer; | |
| 94 | + if (mode.blankLine) { | |
| 95 | + mode.blankLine(state.innerActive ? state.inner : state.outer); | |
| 96 | + } | |
| 97 | + if (!state.innerActive) { | |
| 98 | + for (var i = 0; i < n_others; ++i) { | |
| 99 | + var other = others[i]; | |
| 100 | + if (other.open === "\n") { | |
| 101 | + state.innerActive = other; | |
| 102 | + state.inner = CodeMirror.startState(other.mode, mode.indent ? mode.indent(state.outer, "") : 0); | |
| 103 | + } | |
| 104 | + } | |
| 105 | + } else if (state.innerActive.close === "\n") { | |
| 106 | + state.innerActive = state.inner = null; | |
| 107 | + } | |
| 108 | + }, | |
| 109 | + | |
| 110 | + electricChars: outer.electricChars, | |
| 111 | + | |
| 112 | + innerMode: function(state) { | |
| 113 | + return state.inner ? {state: state.inner, mode: state.innerActive.mode} : {state: state.outer, mode: outer}; | |
| 114 | + } | |
| 115 | + }; | |
| 116 | +}; | |
| 117 | + | |
| 118 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,33 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function() { | |
| 5 | + CodeMirror.defineMode("markdown_with_stex", function(){ | |
| 6 | + var inner = CodeMirror.getMode({}, "stex"); | |
| 7 | + var outer = CodeMirror.getMode({}, "markdown"); | |
| 8 | + | |
| 9 | + var innerOptions = { | |
| 10 | + open: '$', | |
| 11 | + close: '$', | |
| 12 | + mode: inner, | |
| 13 | + delimStyle: 'delim', | |
| 14 | + innerStyle: 'inner' | |
| 15 | + }; | |
| 16 | + | |
| 17 | + return CodeMirror.multiplexingMode(outer, innerOptions); | |
| 18 | + }); | |
| 19 | + | |
| 20 | + var mode = CodeMirror.getMode({}, "markdown_with_stex"); | |
| 21 | + | |
| 22 | + function MT(name) { | |
| 23 | + test.mode( | |
| 24 | + name, | |
| 25 | + mode, | |
| 26 | + Array.prototype.slice.call(arguments, 1), | |
| 27 | + 'multiplexing'); | |
| 28 | + } | |
| 29 | + | |
| 30 | + MT( | |
| 31 | + "stexInsideMarkdown", | |
| 32 | + "[strong **Equation:**] [delim $][inner&tag \\pi][delim $]"); | |
| 33 | +})(); | ... | ... |
| ... | ... | @@ -0,0 +1,85 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +// Utility function that allows modes to be combined. The mode given | |
| 5 | +// as the base argument takes care of most of the normal mode | |
| 6 | +// functionality, but a second (typically simple) mode is used, which | |
| 7 | +// can override the style of text. Both modes get to parse all of the | |
| 8 | +// text, but when both assign a non-null style to a piece of code, the | |
| 9 | +// overlay wins, unless the combine argument was true and not overridden, | |
| 10 | +// or state.overlay.combineTokens was true, in which case the styles are | |
| 11 | +// combined. | |
| 12 | + | |
| 13 | +(function(mod) { | |
| 14 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 15 | + mod(require("../../lib/codemirror")); | |
| 16 | + else if (typeof define == "function" && define.amd) // AMD | |
| 17 | + define(["../../lib/codemirror"], mod); | |
| 18 | + else // Plain browser env | |
| 19 | + mod(CodeMirror); | |
| 20 | +})(function(CodeMirror) { | |
| 21 | +"use strict"; | |
| 22 | + | |
| 23 | +CodeMirror.overlayMode = function(base, overlay, combine) { | |
| 24 | + return { | |
| 25 | + startState: function() { | |
| 26 | + return { | |
| 27 | + base: CodeMirror.startState(base), | |
| 28 | + overlay: CodeMirror.startState(overlay), | |
| 29 | + basePos: 0, baseCur: null, | |
| 30 | + overlayPos: 0, overlayCur: null, | |
| 31 | + lineSeen: null | |
| 32 | + }; | |
| 33 | + }, | |
| 34 | + copyState: function(state) { | |
| 35 | + return { | |
| 36 | + base: CodeMirror.copyState(base, state.base), | |
| 37 | + overlay: CodeMirror.copyState(overlay, state.overlay), | |
| 38 | + basePos: state.basePos, baseCur: null, | |
| 39 | + overlayPos: state.overlayPos, overlayCur: null | |
| 40 | + }; | |
| 41 | + }, | |
| 42 | + | |
| 43 | + token: function(stream, state) { | |
| 44 | + if (stream.sol() || stream.string != state.lineSeen || | |
| 45 | + Math.min(state.basePos, state.overlayPos) < stream.start) { | |
| 46 | + state.lineSeen = stream.string; | |
| 47 | + state.basePos = state.overlayPos = stream.start; | |
| 48 | + } | |
| 49 | + | |
| 50 | + if (stream.start == state.basePos) { | |
| 51 | + state.baseCur = base.token(stream, state.base); | |
| 52 | + state.basePos = stream.pos; | |
| 53 | + } | |
| 54 | + if (stream.start == state.overlayPos) { | |
| 55 | + stream.pos = stream.start; | |
| 56 | + state.overlayCur = overlay.token(stream, state.overlay); | |
| 57 | + state.overlayPos = stream.pos; | |
| 58 | + } | |
| 59 | + stream.pos = Math.min(state.basePos, state.overlayPos); | |
| 60 | + | |
| 61 | + // state.overlay.combineTokens always takes precedence over combine, | |
| 62 | + // unless set to null | |
| 63 | + if (state.overlayCur == null) return state.baseCur; | |
| 64 | + else if (state.baseCur != null && | |
| 65 | + state.overlay.combineTokens || | |
| 66 | + combine && state.overlay.combineTokens == null) | |
| 67 | + return state.baseCur + " " + state.overlayCur; | |
| 68 | + else return state.overlayCur; | |
| 69 | + }, | |
| 70 | + | |
| 71 | + indent: base.indent && function(state, textAfter) { | |
| 72 | + return base.indent(state.base, textAfter); | |
| 73 | + }, | |
| 74 | + electricChars: base.electricChars, | |
| 75 | + | |
| 76 | + innerMode: function(state) { return {state: state.base, mode: base}; }, | |
| 77 | + | |
| 78 | + blankLine: function(state) { | |
| 79 | + if (base.blankLine) base.blankLine(state.base); | |
| 80 | + if (overlay.blankLine) overlay.blankLine(state.overlay); | |
| 81 | + } | |
| 82 | + }; | |
| 83 | +}; | |
| 84 | + | |
| 85 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,40 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror"), require("./runmode")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror", "./runmode"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + "use strict"; | |
| 13 | + | |
| 14 | + var isBlock = /^(p|li|div|h\\d|pre|blockquote|td)$/; | |
| 15 | + | |
| 16 | + function textContent(node, out) { | |
| 17 | + if (node.nodeType == 3) return out.push(node.nodeValue); | |
| 18 | + for (var ch = node.firstChild; ch; ch = ch.nextSibling) { | |
| 19 | + textContent(ch, out); | |
| 20 | + if (isBlock.test(node.nodeType)) out.push("\n"); | |
| 21 | + } | |
| 22 | + } | |
| 23 | + | |
| 24 | + CodeMirror.colorize = function(collection, defaultMode) { | |
| 25 | + if (!collection) collection = document.body.getElementsByTagName("pre"); | |
| 26 | + | |
| 27 | + for (var i = 0; i < collection.length; ++i) { | |
| 28 | + var node = collection[i]; | |
| 29 | + var mode = node.getAttribute("data-lang") || defaultMode; | |
| 30 | + if (!mode) continue; | |
| 31 | + | |
| 32 | + var text = []; | |
| 33 | + textContent(node, text); | |
| 34 | + node.innerHTML = ""; | |
| 35 | + CodeMirror.runMode(text.join(""), mode, node); | |
| 36 | + | |
| 37 | + node.className += " cm-s-default"; | |
| 38 | + } | |
| 39 | + }; | |
| 40 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,153 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +window.CodeMirror = {}; | |
| 5 | + | |
| 6 | +(function() { | |
| 7 | +"use strict"; | |
| 8 | + | |
| 9 | +function splitLines(string){ return string.split(/\r?\n|\r/); }; | |
| 10 | + | |
| 11 | +function StringStream(string) { | |
| 12 | + this.pos = this.start = 0; | |
| 13 | + this.string = string; | |
| 14 | + this.lineStart = 0; | |
| 15 | +} | |
| 16 | +StringStream.prototype = { | |
| 17 | + eol: function() {return this.pos >= this.string.length;}, | |
| 18 | + sol: function() {return this.pos == 0;}, | |
| 19 | + peek: function() {return this.string.charAt(this.pos) || null;}, | |
| 20 | + next: function() { | |
| 21 | + if (this.pos < this.string.length) | |
| 22 | + return this.string.charAt(this.pos++); | |
| 23 | + }, | |
| 24 | + eat: function(match) { | |
| 25 | + var ch = this.string.charAt(this.pos); | |
| 26 | + if (typeof match == "string") var ok = ch == match; | |
| 27 | + else var ok = ch && (match.test ? match.test(ch) : match(ch)); | |
| 28 | + if (ok) {++this.pos; return ch;} | |
| 29 | + }, | |
| 30 | + eatWhile: function(match) { | |
| 31 | + var start = this.pos; | |
| 32 | + while (this.eat(match)){} | |
| 33 | + return this.pos > start; | |
| 34 | + }, | |
| 35 | + eatSpace: function() { | |
| 36 | + var start = this.pos; | |
| 37 | + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; | |
| 38 | + return this.pos > start; | |
| 39 | + }, | |
| 40 | + skipToEnd: function() {this.pos = this.string.length;}, | |
| 41 | + skipTo: function(ch) { | |
| 42 | + var found = this.string.indexOf(ch, this.pos); | |
| 43 | + if (found > -1) {this.pos = found; return true;} | |
| 44 | + }, | |
| 45 | + backUp: function(n) {this.pos -= n;}, | |
| 46 | + column: function() {return this.start - this.lineStart;}, | |
| 47 | + indentation: function() {return 0;}, | |
| 48 | + match: function(pattern, consume, caseInsensitive) { | |
| 49 | + if (typeof pattern == "string") { | |
| 50 | + var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; | |
| 51 | + var substr = this.string.substr(this.pos, pattern.length); | |
| 52 | + if (cased(substr) == cased(pattern)) { | |
| 53 | + if (consume !== false) this.pos += pattern.length; | |
| 54 | + return true; | |
| 55 | + } | |
| 56 | + } else { | |
| 57 | + var match = this.string.slice(this.pos).match(pattern); | |
| 58 | + if (match && match.index > 0) return null; | |
| 59 | + if (match && consume !== false) this.pos += match[0].length; | |
| 60 | + return match; | |
| 61 | + } | |
| 62 | + }, | |
| 63 | + current: function(){return this.string.slice(this.start, this.pos);}, | |
| 64 | + hideFirstChars: function(n, inner) { | |
| 65 | + this.lineStart += n; | |
| 66 | + try { return inner(); } | |
| 67 | + finally { this.lineStart -= n; } | |
| 68 | + } | |
| 69 | +}; | |
| 70 | +CodeMirror.StringStream = StringStream; | |
| 71 | + | |
| 72 | +CodeMirror.startState = function (mode, a1, a2) { | |
| 73 | + return mode.startState ? mode.startState(a1, a2) : true; | |
| 74 | +}; | |
| 75 | + | |
| 76 | +var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {}; | |
| 77 | +CodeMirror.defineMode = function (name, mode) { modes[name] = mode; }; | |
| 78 | +CodeMirror.defineMIME = function (mime, spec) { mimeModes[mime] = spec; }; | |
| 79 | +CodeMirror.resolveMode = function(spec) { | |
| 80 | + if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { | |
| 81 | + spec = mimeModes[spec]; | |
| 82 | + } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { | |
| 83 | + spec = mimeModes[spec.name]; | |
| 84 | + } | |
| 85 | + if (typeof spec == "string") return {name: spec}; | |
| 86 | + else return spec || {name: "null"}; | |
| 87 | +}; | |
| 88 | +CodeMirror.getMode = function (options, spec) { | |
| 89 | + spec = CodeMirror.resolveMode(spec); | |
| 90 | + var mfactory = modes[spec.name]; | |
| 91 | + if (!mfactory) throw new Error("Unknown mode: " + spec); | |
| 92 | + return mfactory(options, spec); | |
| 93 | +}; | |
| 94 | +CodeMirror.registerHelper = CodeMirror.registerGlobalHelper = Math.min; | |
| 95 | +CodeMirror.defineMode("null", function() { | |
| 96 | + return {token: function(stream) {stream.skipToEnd();}}; | |
| 97 | +}); | |
| 98 | +CodeMirror.defineMIME("text/plain", "null"); | |
| 99 | + | |
| 100 | +CodeMirror.runMode = function (string, modespec, callback, options) { | |
| 101 | + var mode = CodeMirror.getMode({ indentUnit: 2 }, modespec); | |
| 102 | + | |
| 103 | + if (callback.nodeType == 1) { | |
| 104 | + var tabSize = (options && options.tabSize) || 4; | |
| 105 | + var node = callback, col = 0; | |
| 106 | + node.innerHTML = ""; | |
| 107 | + callback = function (text, style) { | |
| 108 | + if (text == "\n") { | |
| 109 | + node.appendChild(document.createElement("br")); | |
| 110 | + col = 0; | |
| 111 | + return; | |
| 112 | + } | |
| 113 | + var content = ""; | |
| 114 | + // replace tabs | |
| 115 | + for (var pos = 0; ;) { | |
| 116 | + var idx = text.indexOf("\t", pos); | |
| 117 | + if (idx == -1) { | |
| 118 | + content += text.slice(pos); | |
| 119 | + col += text.length - pos; | |
| 120 | + break; | |
| 121 | + } else { | |
| 122 | + col += idx - pos; | |
| 123 | + content += text.slice(pos, idx); | |
| 124 | + var size = tabSize - col % tabSize; | |
| 125 | + col += size; | |
| 126 | + for (var i = 0; i < size; ++i) content += " "; | |
| 127 | + pos = idx + 1; | |
| 128 | + } | |
| 129 | + } | |
| 130 | + | |
| 131 | + if (style) { | |
| 132 | + var sp = node.appendChild(document.createElement("span")); | |
| 133 | + sp.className = "cm-" + style.replace(/ +/g, " cm-"); | |
| 134 | + sp.appendChild(document.createTextNode(content)); | |
| 135 | + } else { | |
| 136 | + node.appendChild(document.createTextNode(content)); | |
| 137 | + } | |
| 138 | + }; | |
| 139 | + } | |
| 140 | + | |
| 141 | + var lines = splitLines(string), state = (options && options.state) || CodeMirror.startState(mode); | |
| 142 | + for (var i = 0, e = lines.length; i < e; ++i) { | |
| 143 | + if (i) callback("\n"); | |
| 144 | + var stream = new CodeMirror.StringStream(lines[i]); | |
| 145 | + if (!stream.string && mode.blankLine) mode.blankLine(state); | |
| 146 | + while (!stream.eol()) { | |
| 147 | + var style = mode.token(stream, state); | |
| 148 | + callback(stream.current(), style, i, stream.start, state); | |
| 149 | + stream.start = stream.pos; | |
| 150 | + } | |
| 151 | + } | |
| 152 | +}; | |
| 153 | +})(); | ... | ... |
| ... | ... | @@ -0,0 +1,72 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | +"use strict"; | |
| 13 | + | |
| 14 | +CodeMirror.runMode = function(string, modespec, callback, options) { | |
| 15 | + var mode = CodeMirror.getMode(CodeMirror.defaults, modespec); | |
| 16 | + var ie = /MSIE \d/.test(navigator.userAgent); | |
| 17 | + var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9); | |
| 18 | + | |
| 19 | + if (callback.nodeType == 1) { | |
| 20 | + var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize; | |
| 21 | + var node = callback, col = 0; | |
| 22 | + node.innerHTML = ""; | |
| 23 | + callback = function(text, style) { | |
| 24 | + if (text == "\n") { | |
| 25 | + // Emitting LF or CRLF on IE8 or earlier results in an incorrect display. | |
| 26 | + // Emitting a carriage return makes everything ok. | |
| 27 | + node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text)); | |
| 28 | + col = 0; | |
| 29 | + return; | |
| 30 | + } | |
| 31 | + var content = ""; | |
| 32 | + // replace tabs | |
| 33 | + for (var pos = 0;;) { | |
| 34 | + var idx = text.indexOf("\t", pos); | |
| 35 | + if (idx == -1) { | |
| 36 | + content += text.slice(pos); | |
| 37 | + col += text.length - pos; | |
| 38 | + break; | |
| 39 | + } else { | |
| 40 | + col += idx - pos; | |
| 41 | + content += text.slice(pos, idx); | |
| 42 | + var size = tabSize - col % tabSize; | |
| 43 | + col += size; | |
| 44 | + for (var i = 0; i < size; ++i) content += " "; | |
| 45 | + pos = idx + 1; | |
| 46 | + } | |
| 47 | + } | |
| 48 | + | |
| 49 | + if (style) { | |
| 50 | + var sp = node.appendChild(document.createElement("span")); | |
| 51 | + sp.className = "cm-" + style.replace(/ +/g, " cm-"); | |
| 52 | + sp.appendChild(document.createTextNode(content)); | |
| 53 | + } else { | |
| 54 | + node.appendChild(document.createTextNode(content)); | |
| 55 | + } | |
| 56 | + }; | |
| 57 | + } | |
| 58 | + | |
| 59 | + var lines = CodeMirror.splitLines(string), state = (options && options.state) || CodeMirror.startState(mode); | |
| 60 | + for (var i = 0, e = lines.length; i < e; ++i) { | |
| 61 | + if (i) callback("\n"); | |
| 62 | + var stream = new CodeMirror.StringStream(lines[i]); | |
| 63 | + if (!stream.string && mode.blankLine) mode.blankLine(state); | |
| 64 | + while (!stream.eol()) { | |
| 65 | + var style = mode.token(stream, state); | |
| 66 | + callback(stream.current(), style, i, stream.start, state); | |
| 67 | + stream.start = stream.pos; | |
| 68 | + } | |
| 69 | + } | |
| 70 | +}; | |
| 71 | + | |
| 72 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,122 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +/* Just enough of CodeMirror to run runMode under node.js */ | |
| 5 | + | |
| 6 | +// declare global: StringStream | |
| 7 | + | |
| 8 | +function splitLines(string){ return string.split(/\r?\n|\r/); }; | |
| 9 | + | |
| 10 | +function StringStream(string) { | |
| 11 | + this.pos = this.start = 0; | |
| 12 | + this.string = string; | |
| 13 | + this.lineStart = 0; | |
| 14 | +} | |
| 15 | +StringStream.prototype = { | |
| 16 | + eol: function() {return this.pos >= this.string.length;}, | |
| 17 | + sol: function() {return this.pos == 0;}, | |
| 18 | + peek: function() {return this.string.charAt(this.pos) || null;}, | |
| 19 | + next: function() { | |
| 20 | + if (this.pos < this.string.length) | |
| 21 | + return this.string.charAt(this.pos++); | |
| 22 | + }, | |
| 23 | + eat: function(match) { | |
| 24 | + var ch = this.string.charAt(this.pos); | |
| 25 | + if (typeof match == "string") var ok = ch == match; | |
| 26 | + else var ok = ch && (match.test ? match.test(ch) : match(ch)); | |
| 27 | + if (ok) {++this.pos; return ch;} | |
| 28 | + }, | |
| 29 | + eatWhile: function(match) { | |
| 30 | + var start = this.pos; | |
| 31 | + while (this.eat(match)){} | |
| 32 | + return this.pos > start; | |
| 33 | + }, | |
| 34 | + eatSpace: function() { | |
| 35 | + var start = this.pos; | |
| 36 | + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; | |
| 37 | + return this.pos > start; | |
| 38 | + }, | |
| 39 | + skipToEnd: function() {this.pos = this.string.length;}, | |
| 40 | + skipTo: function(ch) { | |
| 41 | + var found = this.string.indexOf(ch, this.pos); | |
| 42 | + if (found > -1) {this.pos = found; return true;} | |
| 43 | + }, | |
| 44 | + backUp: function(n) {this.pos -= n;}, | |
| 45 | + column: function() {return this.start - this.lineStart;}, | |
| 46 | + indentation: function() {return 0;}, | |
| 47 | + match: function(pattern, consume, caseInsensitive) { | |
| 48 | + if (typeof pattern == "string") { | |
| 49 | + var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; | |
| 50 | + var substr = this.string.substr(this.pos, pattern.length); | |
| 51 | + if (cased(substr) == cased(pattern)) { | |
| 52 | + if (consume !== false) this.pos += pattern.length; | |
| 53 | + return true; | |
| 54 | + } | |
| 55 | + } else { | |
| 56 | + var match = this.string.slice(this.pos).match(pattern); | |
| 57 | + if (match && match.index > 0) return null; | |
| 58 | + if (match && consume !== false) this.pos += match[0].length; | |
| 59 | + return match; | |
| 60 | + } | |
| 61 | + }, | |
| 62 | + current: function(){return this.string.slice(this.start, this.pos);}, | |
| 63 | + hideFirstChars: function(n, inner) { | |
| 64 | + this.lineStart += n; | |
| 65 | + try { return inner(); } | |
| 66 | + finally { this.lineStart -= n; } | |
| 67 | + } | |
| 68 | +}; | |
| 69 | +exports.StringStream = StringStream; | |
| 70 | + | |
| 71 | +exports.startState = function(mode, a1, a2) { | |
| 72 | + return mode.startState ? mode.startState(a1, a2) : true; | |
| 73 | +}; | |
| 74 | + | |
| 75 | +var modes = exports.modes = {}, mimeModes = exports.mimeModes = {}; | |
| 76 | +exports.defineMode = function(name, mode) { | |
| 77 | + if (arguments.length > 2) { | |
| 78 | + mode.dependencies = []; | |
| 79 | + for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]); | |
| 80 | + } | |
| 81 | + modes[name] = mode; | |
| 82 | +}; | |
| 83 | +exports.defineMIME = function(mime, spec) { mimeModes[mime] = spec; }; | |
| 84 | + | |
| 85 | +exports.defineMode("null", function() { | |
| 86 | + return {token: function(stream) {stream.skipToEnd();}}; | |
| 87 | +}); | |
| 88 | +exports.defineMIME("text/plain", "null"); | |
| 89 | + | |
| 90 | +exports.resolveMode = function(spec) { | |
| 91 | + if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { | |
| 92 | + spec = mimeModes[spec]; | |
| 93 | + } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { | |
| 94 | + spec = mimeModes[spec.name]; | |
| 95 | + } | |
| 96 | + if (typeof spec == "string") return {name: spec}; | |
| 97 | + else return spec || {name: "null"}; | |
| 98 | +}; | |
| 99 | +exports.getMode = function(options, spec) { | |
| 100 | + spec = exports.resolveMode(spec); | |
| 101 | + var mfactory = modes[spec.name]; | |
| 102 | + if (!mfactory) throw new Error("Unknown mode: " + spec); | |
| 103 | + return mfactory(options, spec); | |
| 104 | +}; | |
| 105 | +exports.registerHelper = exports.registerGlobalHelper = Math.min; | |
| 106 | + | |
| 107 | +exports.runMode = function(string, modespec, callback, options) { | |
| 108 | + var mode = exports.getMode({indentUnit: 2}, modespec); | |
| 109 | + var lines = splitLines(string), state = (options && options.state) || exports.startState(mode); | |
| 110 | + for (var i = 0, e = lines.length; i < e; ++i) { | |
| 111 | + if (i) callback("\n"); | |
| 112 | + var stream = new exports.StringStream(lines[i]); | |
| 113 | + if (!stream.string && mode.blankLine) mode.blankLine(state); | |
| 114 | + while (!stream.eol()) { | |
| 115 | + var style = mode.token(stream, state); | |
| 116 | + callback(stream.current(), style, i, stream.start, state); | |
| 117 | + stream.start = stream.pos; | |
| 118 | + } | |
| 119 | + } | |
| 120 | +}; | |
| 121 | + | |
| 122 | +require.cache[require.resolve("../../lib/codemirror")] = require.cache[require.resolve("./runmode.node")]; | ... | ... |
| ... | ... | @@ -0,0 +1,46 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + "use strict"; | |
| 13 | + | |
| 14 | + CodeMirror.defineOption("scrollPastEnd", false, function(cm, val, old) { | |
| 15 | + if (old && old != CodeMirror.Init) { | |
| 16 | + cm.off("change", onChange); | |
| 17 | + cm.off("refresh", updateBottomMargin); | |
| 18 | + cm.display.lineSpace.parentNode.style.paddingBottom = ""; | |
| 19 | + cm.state.scrollPastEndPadding = null; | |
| 20 | + } | |
| 21 | + if (val) { | |
| 22 | + cm.on("change", onChange); | |
| 23 | + cm.on("refresh", updateBottomMargin); | |
| 24 | + updateBottomMargin(cm); | |
| 25 | + } | |
| 26 | + }); | |
| 27 | + | |
| 28 | + function onChange(cm, change) { | |
| 29 | + if (CodeMirror.changeEnd(change).line == cm.lastLine()) | |
| 30 | + updateBottomMargin(cm); | |
| 31 | + } | |
| 32 | + | |
| 33 | + function updateBottomMargin(cm) { | |
| 34 | + var padding = ""; | |
| 35 | + if (cm.lineCount() > 1) { | |
| 36 | + var totalH = cm.display.scroller.clientHeight - 30, | |
| 37 | + lastLineH = cm.getLineHandle(cm.lastLine()).height; | |
| 38 | + padding = (totalH - lastLineH) + "px"; | |
| 39 | + } | |
| 40 | + if (cm.state.scrollPastEndPadding != padding) { | |
| 41 | + cm.state.scrollPastEndPadding = padding; | |
| 42 | + cm.display.lineSpace.parentNode.style.paddingBottom = padding; | |
| 43 | + cm.setSize(); | |
| 44 | + } | |
| 45 | + } | |
| 46 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,128 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +// Highlighting text that matches the selection | |
| 5 | +// | |
| 6 | +// Defines an option highlightSelectionMatches, which, when enabled, | |
| 7 | +// will style strings that match the selection throughout the | |
| 8 | +// document. | |
| 9 | +// | |
| 10 | +// The option can be set to true to simply enable it, or to a | |
| 11 | +// {minChars, style, wordsOnly, showToken, delay} object to explicitly | |
| 12 | +// configure it. minChars is the minimum amount of characters that should be | |
| 13 | +// selected for the behavior to occur, and style is the token style to | |
| 14 | +// apply to the matches. This will be prefixed by "cm-" to create an | |
| 15 | +// actual CSS class name. If wordsOnly is enabled, the matches will be | |
| 16 | +// highlighted only if the selected text is a word. showToken, when enabled, | |
| 17 | +// will cause the current token to be highlighted when nothing is selected. | |
| 18 | +// delay is used to specify how much time to wait, in milliseconds, before | |
| 19 | +// highlighting the matches. | |
| 20 | + | |
| 21 | +(function(mod) { | |
| 22 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 23 | + mod(require("../../lib/codemirror")); | |
| 24 | + else if (typeof define == "function" && define.amd) // AMD | |
| 25 | + define(["../../lib/codemirror"], mod); | |
| 26 | + else // Plain browser env | |
| 27 | + mod(CodeMirror); | |
| 28 | +})(function(CodeMirror) { | |
| 29 | + "use strict"; | |
| 30 | + | |
| 31 | + var DEFAULT_MIN_CHARS = 2; | |
| 32 | + var DEFAULT_TOKEN_STYLE = "matchhighlight"; | |
| 33 | + var DEFAULT_DELAY = 100; | |
| 34 | + var DEFAULT_WORDS_ONLY = false; | |
| 35 | + | |
| 36 | + function State(options) { | |
| 37 | + if (typeof options == "object") { | |
| 38 | + this.minChars = options.minChars; | |
| 39 | + this.style = options.style; | |
| 40 | + this.showToken = options.showToken; | |
| 41 | + this.delay = options.delay; | |
| 42 | + this.wordsOnly = options.wordsOnly; | |
| 43 | + } | |
| 44 | + if (this.style == null) this.style = DEFAULT_TOKEN_STYLE; | |
| 45 | + if (this.minChars == null) this.minChars = DEFAULT_MIN_CHARS; | |
| 46 | + if (this.delay == null) this.delay = DEFAULT_DELAY; | |
| 47 | + if (this.wordsOnly == null) this.wordsOnly = DEFAULT_WORDS_ONLY; | |
| 48 | + this.overlay = this.timeout = null; | |
| 49 | + } | |
| 50 | + | |
| 51 | + CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) { | |
| 52 | + if (old && old != CodeMirror.Init) { | |
| 53 | + var over = cm.state.matchHighlighter.overlay; | |
| 54 | + if (over) cm.removeOverlay(over); | |
| 55 | + clearTimeout(cm.state.matchHighlighter.timeout); | |
| 56 | + cm.state.matchHighlighter = null; | |
| 57 | + cm.off("cursorActivity", cursorActivity); | |
| 58 | + } | |
| 59 | + if (val) { | |
| 60 | + cm.state.matchHighlighter = new State(val); | |
| 61 | + highlightMatches(cm); | |
| 62 | + cm.on("cursorActivity", cursorActivity); | |
| 63 | + } | |
| 64 | + }); | |
| 65 | + | |
| 66 | + function cursorActivity(cm) { | |
| 67 | + var state = cm.state.matchHighlighter; | |
| 68 | + clearTimeout(state.timeout); | |
| 69 | + state.timeout = setTimeout(function() {highlightMatches(cm);}, state.delay); | |
| 70 | + } | |
| 71 | + | |
| 72 | + function highlightMatches(cm) { | |
| 73 | + cm.operation(function() { | |
| 74 | + var state = cm.state.matchHighlighter; | |
| 75 | + if (state.overlay) { | |
| 76 | + cm.removeOverlay(state.overlay); | |
| 77 | + state.overlay = null; | |
| 78 | + } | |
| 79 | + if (!cm.somethingSelected() && state.showToken) { | |
| 80 | + var re = state.showToken === true ? /[\w$]/ : state.showToken; | |
| 81 | + var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start; | |
| 82 | + while (start && re.test(line.charAt(start - 1))) --start; | |
| 83 | + while (end < line.length && re.test(line.charAt(end))) ++end; | |
| 84 | + if (start < end) | |
| 85 | + cm.addOverlay(state.overlay = makeOverlay(line.slice(start, end), re, state.style)); | |
| 86 | + return; | |
| 87 | + } | |
| 88 | + var from = cm.getCursor("from"), to = cm.getCursor("to"); | |
| 89 | + if (from.line != to.line) return; | |
| 90 | + if (state.wordsOnly && !isWord(cm, from, to)) return; | |
| 91 | + var selection = cm.getRange(from, to).replace(/^\s+|\s+$/g, ""); | |
| 92 | + if (selection.length >= state.minChars) | |
| 93 | + cm.addOverlay(state.overlay = makeOverlay(selection, false, state.style)); | |
| 94 | + }); | |
| 95 | + } | |
| 96 | + | |
| 97 | + function isWord(cm, from, to) { | |
| 98 | + var str = cm.getRange(from, to); | |
| 99 | + if (str.match(/^\w+$/) !== null) { | |
| 100 | + if (from.ch > 0) { | |
| 101 | + var pos = {line: from.line, ch: from.ch - 1}; | |
| 102 | + var chr = cm.getRange(pos, from); | |
| 103 | + if (chr.match(/\W/) === null) return false; | |
| 104 | + } | |
| 105 | + if (to.ch < cm.getLine(from.line).length) { | |
| 106 | + var pos = {line: to.line, ch: to.ch + 1}; | |
| 107 | + var chr = cm.getRange(to, pos); | |
| 108 | + if (chr.match(/\W/) === null) return false; | |
| 109 | + } | |
| 110 | + return true; | |
| 111 | + } else return false; | |
| 112 | + } | |
| 113 | + | |
| 114 | + function boundariesAround(stream, re) { | |
| 115 | + return (!stream.start || !re.test(stream.string.charAt(stream.start - 1))) && | |
| 116 | + (stream.pos == stream.string.length || !re.test(stream.string.charAt(stream.pos))); | |
| 117 | + } | |
| 118 | + | |
| 119 | + function makeOverlay(query, hasBoundary, style) { | |
| 120 | + return {token: function(stream) { | |
| 121 | + if (stream.match(query) && | |
| 122 | + (!hasBoundary || boundariesAround(stream, hasBoundary))) | |
| 123 | + return style; | |
| 124 | + stream.next(); | |
| 125 | + stream.skipTo(query.charAt(0)) || stream.skipToEnd(); | |
| 126 | + }}; | |
| 127 | + } | |
| 128 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,159 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +// Define search commands. Depends on dialog.js or another | |
| 5 | +// implementation of the openDialog method. | |
| 6 | + | |
| 7 | +// Replace works a little oddly -- it will do the replace on the next | |
| 8 | +// Ctrl-G (or whatever is bound to findNext) press. You prevent a | |
| 9 | +// replace by making sure the match is no longer selected when hitting | |
| 10 | +// Ctrl-G. | |
| 11 | + | |
| 12 | +(function(mod) { | |
| 13 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 14 | + mod(require("../../lib/codemirror"), require("./searchcursor"), require("../dialog/dialog")); | |
| 15 | + else if (typeof define == "function" && define.amd) // AMD | |
| 16 | + define(["../../lib/codemirror", "./searchcursor", "../dialog/dialog"], mod); | |
| 17 | + else // Plain browser env | |
| 18 | + mod(CodeMirror); | |
| 19 | +})(function(CodeMirror) { | |
| 20 | + "use strict"; | |
| 21 | + function searchOverlay(query, caseInsensitive) { | |
| 22 | + if (typeof query == "string") | |
| 23 | + query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g"); | |
| 24 | + else if (!query.global) | |
| 25 | + query = new RegExp(query.source, query.ignoreCase ? "gi" : "g"); | |
| 26 | + | |
| 27 | + return {token: function(stream) { | |
| 28 | + query.lastIndex = stream.pos; | |
| 29 | + var match = query.exec(stream.string); | |
| 30 | + if (match && match.index == stream.pos) { | |
| 31 | + stream.pos += match[0].length; | |
| 32 | + return "searching"; | |
| 33 | + } else if (match) { | |
| 34 | + stream.pos = match.index; | |
| 35 | + } else { | |
| 36 | + stream.skipToEnd(); | |
| 37 | + } | |
| 38 | + }}; | |
| 39 | + } | |
| 40 | + | |
| 41 | + function SearchState() { | |
| 42 | + this.posFrom = this.posTo = this.query = null; | |
| 43 | + this.overlay = null; | |
| 44 | + } | |
| 45 | + function getSearchState(cm) { | |
| 46 | + return cm.state.search || (cm.state.search = new SearchState()); | |
| 47 | + } | |
| 48 | + function queryCaseInsensitive(query) { | |
| 49 | + return typeof query == "string" && query == query.toLowerCase(); | |
| 50 | + } | |
| 51 | + function getSearchCursor(cm, query, pos) { | |
| 52 | + // Heuristic: if the query string is all lowercase, do a case insensitive search. | |
| 53 | + return cm.getSearchCursor(query, pos, queryCaseInsensitive(query)); | |
| 54 | + } | |
| 55 | + function dialog(cm, text, shortText, deflt, f) { | |
| 56 | + if (cm.openDialog) cm.openDialog(text, f, {value: deflt}); | |
| 57 | + else f(prompt(shortText, deflt)); | |
| 58 | + } | |
| 59 | + function confirmDialog(cm, text, shortText, fs) { | |
| 60 | + if (cm.openConfirm) cm.openConfirm(text, fs); | |
| 61 | + else if (confirm(shortText)) fs[0](); | |
| 62 | + } | |
| 63 | + function parseQuery(query) { | |
| 64 | + var isRE = query.match(/^\/(.*)\/([a-z]*)$/); | |
| 65 | + if (isRE) { | |
| 66 | + query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); | |
| 67 | + if (query.test("")) query = /x^/; | |
| 68 | + } else if (query == "") { | |
| 69 | + query = /x^/; | |
| 70 | + } | |
| 71 | + return query; | |
| 72 | + } | |
| 73 | + var queryDialog = | |
| 74 | + 'Search: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>'; | |
| 75 | + function doSearch(cm, rev) { | |
| 76 | + var state = getSearchState(cm); | |
| 77 | + if (state.query) return findNext(cm, rev); | |
| 78 | + dialog(cm, queryDialog, "Search for:", cm.getSelection(), function(query) { | |
| 79 | + cm.operation(function() { | |
| 80 | + if (!query || state.query) return; | |
| 81 | + state.query = parseQuery(query); | |
| 82 | + cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query)); | |
| 83 | + state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query)); | |
| 84 | + cm.addOverlay(state.overlay); | |
| 85 | + state.posFrom = state.posTo = cm.getCursor(); | |
| 86 | + findNext(cm, rev); | |
| 87 | + }); | |
| 88 | + }); | |
| 89 | + } | |
| 90 | + function findNext(cm, rev) {cm.operation(function() { | |
| 91 | + var state = getSearchState(cm); | |
| 92 | + var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo); | |
| 93 | + if (!cursor.find(rev)) { | |
| 94 | + cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0)); | |
| 95 | + if (!cursor.find(rev)) return; | |
| 96 | + } | |
| 97 | + cm.setSelection(cursor.from(), cursor.to()); | |
| 98 | + cm.scrollIntoView({from: cursor.from(), to: cursor.to()}); | |
| 99 | + state.posFrom = cursor.from(); state.posTo = cursor.to(); | |
| 100 | + });} | |
| 101 | + function clearSearch(cm) {cm.operation(function() { | |
| 102 | + var state = getSearchState(cm); | |
| 103 | + if (!state.query) return; | |
| 104 | + state.query = null; | |
| 105 | + cm.removeOverlay(state.overlay); | |
| 106 | + });} | |
| 107 | + | |
| 108 | + var replaceQueryDialog = | |
| 109 | + 'Replace: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>'; | |
| 110 | + var replacementQueryDialog = 'With: <input type="text" style="width: 10em" class="CodeMirror-search-field"/>'; | |
| 111 | + var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>Stop</button>"; | |
| 112 | + function replace(cm, all) { | |
| 113 | + if (cm.getOption("readOnly")) return; | |
| 114 | + dialog(cm, replaceQueryDialog, "Replace:", cm.getSelection(), function(query) { | |
| 115 | + if (!query) return; | |
| 116 | + query = parseQuery(query); | |
| 117 | + dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) { | |
| 118 | + if (all) { | |
| 119 | + cm.operation(function() { | |
| 120 | + for (var cursor = getSearchCursor(cm, query); cursor.findNext();) { | |
| 121 | + if (typeof query != "string") { | |
| 122 | + var match = cm.getRange(cursor.from(), cursor.to()).match(query); | |
| 123 | + cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];})); | |
| 124 | + } else cursor.replace(text); | |
| 125 | + } | |
| 126 | + }); | |
| 127 | + } else { | |
| 128 | + clearSearch(cm); | |
| 129 | + var cursor = getSearchCursor(cm, query, cm.getCursor()); | |
| 130 | + var advance = function() { | |
| 131 | + var start = cursor.from(), match; | |
| 132 | + if (!(match = cursor.findNext())) { | |
| 133 | + cursor = getSearchCursor(cm, query); | |
| 134 | + if (!(match = cursor.findNext()) || | |
| 135 | + (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return; | |
| 136 | + } | |
| 137 | + cm.setSelection(cursor.from(), cursor.to()); | |
| 138 | + cm.scrollIntoView({from: cursor.from(), to: cursor.to()}); | |
| 139 | + confirmDialog(cm, doReplaceConfirm, "Replace?", | |
| 140 | + [function() {doReplace(match);}, advance]); | |
| 141 | + }; | |
| 142 | + var doReplace = function(match) { | |
| 143 | + cursor.replace(typeof query == "string" ? text : | |
| 144 | + text.replace(/\$(\d)/g, function(_, i) {return match[i];})); | |
| 145 | + advance(); | |
| 146 | + }; | |
| 147 | + advance(); | |
| 148 | + } | |
| 149 | + }); | |
| 150 | + }); | |
| 151 | + } | |
| 152 | + | |
| 153 | + CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);}; | |
| 154 | + CodeMirror.commands.findNext = doSearch; | |
| 155 | + CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);}; | |
| 156 | + CodeMirror.commands.clearSearch = clearSearch; | |
| 157 | + CodeMirror.commands.replace = replace; | |
| 158 | + CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);}; | |
| 159 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,189 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + "use strict"; | |
| 13 | + var Pos = CodeMirror.Pos; | |
| 14 | + | |
| 15 | + function SearchCursor(doc, query, pos, caseFold) { | |
| 16 | + this.atOccurrence = false; this.doc = doc; | |
| 17 | + if (caseFold == null && typeof query == "string") caseFold = false; | |
| 18 | + | |
| 19 | + pos = pos ? doc.clipPos(pos) : Pos(0, 0); | |
| 20 | + this.pos = {from: pos, to: pos}; | |
| 21 | + | |
| 22 | + // The matches method is filled in based on the type of query. | |
| 23 | + // It takes a position and a direction, and returns an object | |
| 24 | + // describing the next occurrence of the query, or null if no | |
| 25 | + // more matches were found. | |
| 26 | + if (typeof query != "string") { // Regexp match | |
| 27 | + if (!query.global) query = new RegExp(query.source, query.ignoreCase ? "ig" : "g"); | |
| 28 | + this.matches = function(reverse, pos) { | |
| 29 | + if (reverse) { | |
| 30 | + query.lastIndex = 0; | |
| 31 | + var line = doc.getLine(pos.line).slice(0, pos.ch), cutOff = 0, match, start; | |
| 32 | + for (;;) { | |
| 33 | + query.lastIndex = cutOff; | |
| 34 | + var newMatch = query.exec(line); | |
| 35 | + if (!newMatch) break; | |
| 36 | + match = newMatch; | |
| 37 | + start = match.index; | |
| 38 | + cutOff = match.index + (match[0].length || 1); | |
| 39 | + if (cutOff == line.length) break; | |
| 40 | + } | |
| 41 | + var matchLen = (match && match[0].length) || 0; | |
| 42 | + if (!matchLen) { | |
| 43 | + if (start == 0 && line.length == 0) {match = undefined;} | |
| 44 | + else if (start != doc.getLine(pos.line).length) { | |
| 45 | + matchLen++; | |
| 46 | + } | |
| 47 | + } | |
| 48 | + } else { | |
| 49 | + query.lastIndex = pos.ch; | |
| 50 | + var line = doc.getLine(pos.line), match = query.exec(line); | |
| 51 | + var matchLen = (match && match[0].length) || 0; | |
| 52 | + var start = match && match.index; | |
| 53 | + if (start + matchLen != line.length && !matchLen) matchLen = 1; | |
| 54 | + } | |
| 55 | + if (match && matchLen) | |
| 56 | + return {from: Pos(pos.line, start), | |
| 57 | + to: Pos(pos.line, start + matchLen), | |
| 58 | + match: match}; | |
| 59 | + }; | |
| 60 | + } else { // String query | |
| 61 | + var origQuery = query; | |
| 62 | + if (caseFold) query = query.toLowerCase(); | |
| 63 | + var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;}; | |
| 64 | + var target = query.split("\n"); | |
| 65 | + // Different methods for single-line and multi-line queries | |
| 66 | + if (target.length == 1) { | |
| 67 | + if (!query.length) { | |
| 68 | + // Empty string would match anything and never progress, so | |
| 69 | + // we define it to match nothing instead. | |
| 70 | + this.matches = function() {}; | |
| 71 | + } else { | |
| 72 | + this.matches = function(reverse, pos) { | |
| 73 | + if (reverse) { | |
| 74 | + var orig = doc.getLine(pos.line).slice(0, pos.ch), line = fold(orig); | |
| 75 | + var match = line.lastIndexOf(query); | |
| 76 | + if (match > -1) { | |
| 77 | + match = adjustPos(orig, line, match); | |
| 78 | + return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)}; | |
| 79 | + } | |
| 80 | + } else { | |
| 81 | + var orig = doc.getLine(pos.line).slice(pos.ch), line = fold(orig); | |
| 82 | + var match = line.indexOf(query); | |
| 83 | + if (match > -1) { | |
| 84 | + match = adjustPos(orig, line, match) + pos.ch; | |
| 85 | + return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)}; | |
| 86 | + } | |
| 87 | + } | |
| 88 | + }; | |
| 89 | + } | |
| 90 | + } else { | |
| 91 | + var origTarget = origQuery.split("\n"); | |
| 92 | + this.matches = function(reverse, pos) { | |
| 93 | + var last = target.length - 1; | |
| 94 | + if (reverse) { | |
| 95 | + if (pos.line - (target.length - 1) < doc.firstLine()) return; | |
| 96 | + if (fold(doc.getLine(pos.line).slice(0, origTarget[last].length)) != target[target.length - 1]) return; | |
| 97 | + var to = Pos(pos.line, origTarget[last].length); | |
| 98 | + for (var ln = pos.line - 1, i = last - 1; i >= 1; --i, --ln) | |
| 99 | + if (target[i] != fold(doc.getLine(ln))) return; | |
| 100 | + var line = doc.getLine(ln), cut = line.length - origTarget[0].length; | |
| 101 | + if (fold(line.slice(cut)) != target[0]) return; | |
| 102 | + return {from: Pos(ln, cut), to: to}; | |
| 103 | + } else { | |
| 104 | + if (pos.line + (target.length - 1) > doc.lastLine()) return; | |
| 105 | + var line = doc.getLine(pos.line), cut = line.length - origTarget[0].length; | |
| 106 | + if (fold(line.slice(cut)) != target[0]) return; | |
| 107 | + var from = Pos(pos.line, cut); | |
| 108 | + for (var ln = pos.line + 1, i = 1; i < last; ++i, ++ln) | |
| 109 | + if (target[i] != fold(doc.getLine(ln))) return; | |
| 110 | + if (fold(doc.getLine(ln).slice(0, origTarget[last].length)) != target[last]) return; | |
| 111 | + return {from: from, to: Pos(ln, origTarget[last].length)}; | |
| 112 | + } | |
| 113 | + }; | |
| 114 | + } | |
| 115 | + } | |
| 116 | + } | |
| 117 | + | |
| 118 | + SearchCursor.prototype = { | |
| 119 | + findNext: function() {return this.find(false);}, | |
| 120 | + findPrevious: function() {return this.find(true);}, | |
| 121 | + | |
| 122 | + find: function(reverse) { | |
| 123 | + var self = this, pos = this.doc.clipPos(reverse ? this.pos.from : this.pos.to); | |
| 124 | + function savePosAndFail(line) { | |
| 125 | + var pos = Pos(line, 0); | |
| 126 | + self.pos = {from: pos, to: pos}; | |
| 127 | + self.atOccurrence = false; | |
| 128 | + return false; | |
| 129 | + } | |
| 130 | + | |
| 131 | + for (;;) { | |
| 132 | + if (this.pos = this.matches(reverse, pos)) { | |
| 133 | + this.atOccurrence = true; | |
| 134 | + return this.pos.match || true; | |
| 135 | + } | |
| 136 | + if (reverse) { | |
| 137 | + if (!pos.line) return savePosAndFail(0); | |
| 138 | + pos = Pos(pos.line-1, this.doc.getLine(pos.line-1).length); | |
| 139 | + } | |
| 140 | + else { | |
| 141 | + var maxLine = this.doc.lineCount(); | |
| 142 | + if (pos.line == maxLine - 1) return savePosAndFail(maxLine); | |
| 143 | + pos = Pos(pos.line + 1, 0); | |
| 144 | + } | |
| 145 | + } | |
| 146 | + }, | |
| 147 | + | |
| 148 | + from: function() {if (this.atOccurrence) return this.pos.from;}, | |
| 149 | + to: function() {if (this.atOccurrence) return this.pos.to;}, | |
| 150 | + | |
| 151 | + replace: function(newText) { | |
| 152 | + if (!this.atOccurrence) return; | |
| 153 | + var lines = CodeMirror.splitLines(newText); | |
| 154 | + this.doc.replaceRange(lines, this.pos.from, this.pos.to); | |
| 155 | + this.pos.to = Pos(this.pos.from.line + lines.length - 1, | |
| 156 | + lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0)); | |
| 157 | + } | |
| 158 | + }; | |
| 159 | + | |
| 160 | + // Maps a position in a case-folded line back to a position in the original line | |
| 161 | + // (compensating for codepoints increasing in number during folding) | |
| 162 | + function adjustPos(orig, folded, pos) { | |
| 163 | + if (orig.length == folded.length) return pos; | |
| 164 | + for (var pos1 = Math.min(pos, orig.length);;) { | |
| 165 | + var len1 = orig.slice(0, pos1).toLowerCase().length; | |
| 166 | + if (len1 < pos) ++pos1; | |
| 167 | + else if (len1 > pos) --pos1; | |
| 168 | + else return pos1; | |
| 169 | + } | |
| 170 | + } | |
| 171 | + | |
| 172 | + CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) { | |
| 173 | + return new SearchCursor(this.doc, query, pos, caseFold); | |
| 174 | + }); | |
| 175 | + CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) { | |
| 176 | + return new SearchCursor(this, query, pos, caseFold); | |
| 177 | + }); | |
| 178 | + | |
| 179 | + CodeMirror.defineExtension("selectMatches", function(query, caseFold) { | |
| 180 | + var ranges = [], next; | |
| 181 | + var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold); | |
| 182 | + while (next = cur.findNext()) { | |
| 183 | + if (CodeMirror.cmpPos(cur.to(), this.getCursor("to")) > 0) break; | |
| 184 | + ranges.push({anchor: cur.from(), head: cur.to()}); | |
| 185 | + } | |
| 186 | + if (ranges.length) | |
| 187 | + this.setSelections(ranges, 0); | |
| 188 | + }); | |
| 189 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,71 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +// Because sometimes you need to style the cursor's line. | |
| 5 | +// | |
| 6 | +// Adds an option 'styleActiveLine' which, when enabled, gives the | |
| 7 | +// active line's wrapping <div> the CSS class "CodeMirror-activeline", | |
| 8 | +// and gives its background <div> the class "CodeMirror-activeline-background". | |
| 9 | + | |
| 10 | +(function(mod) { | |
| 11 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 12 | + mod(require("../../lib/codemirror")); | |
| 13 | + else if (typeof define == "function" && define.amd) // AMD | |
| 14 | + define(["../../lib/codemirror"], mod); | |
| 15 | + else // Plain browser env | |
| 16 | + mod(CodeMirror); | |
| 17 | +})(function(CodeMirror) { | |
| 18 | + "use strict"; | |
| 19 | + var WRAP_CLASS = "CodeMirror-activeline"; | |
| 20 | + var BACK_CLASS = "CodeMirror-activeline-background"; | |
| 21 | + | |
| 22 | + CodeMirror.defineOption("styleActiveLine", false, function(cm, val, old) { | |
| 23 | + var prev = old && old != CodeMirror.Init; | |
| 24 | + if (val && !prev) { | |
| 25 | + cm.state.activeLines = []; | |
| 26 | + updateActiveLines(cm, cm.listSelections()); | |
| 27 | + cm.on("beforeSelectionChange", selectionChange); | |
| 28 | + } else if (!val && prev) { | |
| 29 | + cm.off("beforeSelectionChange", selectionChange); | |
| 30 | + clearActiveLines(cm); | |
| 31 | + delete cm.state.activeLines; | |
| 32 | + } | |
| 33 | + }); | |
| 34 | + | |
| 35 | + function clearActiveLines(cm) { | |
| 36 | + for (var i = 0; i < cm.state.activeLines.length; i++) { | |
| 37 | + cm.removeLineClass(cm.state.activeLines[i], "wrap", WRAP_CLASS); | |
| 38 | + cm.removeLineClass(cm.state.activeLines[i], "background", BACK_CLASS); | |
| 39 | + } | |
| 40 | + } | |
| 41 | + | |
| 42 | + function sameArray(a, b) { | |
| 43 | + if (a.length != b.length) return false; | |
| 44 | + for (var i = 0; i < a.length; i++) | |
| 45 | + if (a[i] != b[i]) return false; | |
| 46 | + return true; | |
| 47 | + } | |
| 48 | + | |
| 49 | + function updateActiveLines(cm, ranges) { | |
| 50 | + var active = []; | |
| 51 | + for (var i = 0; i < ranges.length; i++) { | |
| 52 | + var range = ranges[i]; | |
| 53 | + if (!range.empty()) continue; | |
| 54 | + var line = cm.getLineHandleVisualStart(range.head.line); | |
| 55 | + if (active[active.length - 1] != line) active.push(line); | |
| 56 | + } | |
| 57 | + if (sameArray(cm.state.activeLines, active)) return; | |
| 58 | + cm.operation(function() { | |
| 59 | + clearActiveLines(cm); | |
| 60 | + for (var i = 0; i < active.length; i++) { | |
| 61 | + cm.addLineClass(active[i], "wrap", WRAP_CLASS); | |
| 62 | + cm.addLineClass(active[i], "background", BACK_CLASS); | |
| 63 | + } | |
| 64 | + cm.state.activeLines = active; | |
| 65 | + }); | |
| 66 | + } | |
| 67 | + | |
| 68 | + function selectionChange(cm, sel) { | |
| 69 | + updateActiveLines(cm, sel.ranges); | |
| 70 | + } | |
| 71 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,118 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +// Because sometimes you need to mark the selected *text*. | |
| 5 | +// | |
| 6 | +// Adds an option 'styleSelectedText' which, when enabled, gives | |
| 7 | +// selected text the CSS class given as option value, or | |
| 8 | +// "CodeMirror-selectedtext" when the value is not a string. | |
| 9 | + | |
| 10 | +(function(mod) { | |
| 11 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 12 | + mod(require("../../lib/codemirror")); | |
| 13 | + else if (typeof define == "function" && define.amd) // AMD | |
| 14 | + define(["../../lib/codemirror"], mod); | |
| 15 | + else // Plain browser env | |
| 16 | + mod(CodeMirror); | |
| 17 | +})(function(CodeMirror) { | |
| 18 | + "use strict"; | |
| 19 | + | |
| 20 | + CodeMirror.defineOption("styleSelectedText", false, function(cm, val, old) { | |
| 21 | + var prev = old && old != CodeMirror.Init; | |
| 22 | + if (val && !prev) { | |
| 23 | + cm.state.markedSelection = []; | |
| 24 | + cm.state.markedSelectionStyle = typeof val == "string" ? val : "CodeMirror-selectedtext"; | |
| 25 | + reset(cm); | |
| 26 | + cm.on("cursorActivity", onCursorActivity); | |
| 27 | + cm.on("change", onChange); | |
| 28 | + } else if (!val && prev) { | |
| 29 | + cm.off("cursorActivity", onCursorActivity); | |
| 30 | + cm.off("change", onChange); | |
| 31 | + clear(cm); | |
| 32 | + cm.state.markedSelection = cm.state.markedSelectionStyle = null; | |
| 33 | + } | |
| 34 | + }); | |
| 35 | + | |
| 36 | + function onCursorActivity(cm) { | |
| 37 | + cm.operation(function() { update(cm); }); | |
| 38 | + } | |
| 39 | + | |
| 40 | + function onChange(cm) { | |
| 41 | + if (cm.state.markedSelection.length) | |
| 42 | + cm.operation(function() { clear(cm); }); | |
| 43 | + } | |
| 44 | + | |
| 45 | + var CHUNK_SIZE = 8; | |
| 46 | + var Pos = CodeMirror.Pos; | |
| 47 | + var cmp = CodeMirror.cmpPos; | |
| 48 | + | |
| 49 | + function coverRange(cm, from, to, addAt) { | |
| 50 | + if (cmp(from, to) == 0) return; | |
| 51 | + var array = cm.state.markedSelection; | |
| 52 | + var cls = cm.state.markedSelectionStyle; | |
| 53 | + for (var line = from.line;;) { | |
| 54 | + var start = line == from.line ? from : Pos(line, 0); | |
| 55 | + var endLine = line + CHUNK_SIZE, atEnd = endLine >= to.line; | |
| 56 | + var end = atEnd ? to : Pos(endLine, 0); | |
| 57 | + var mark = cm.markText(start, end, {className: cls}); | |
| 58 | + if (addAt == null) array.push(mark); | |
| 59 | + else array.splice(addAt++, 0, mark); | |
| 60 | + if (atEnd) break; | |
| 61 | + line = endLine; | |
| 62 | + } | |
| 63 | + } | |
| 64 | + | |
| 65 | + function clear(cm) { | |
| 66 | + var array = cm.state.markedSelection; | |
| 67 | + for (var i = 0; i < array.length; ++i) array[i].clear(); | |
| 68 | + array.length = 0; | |
| 69 | + } | |
| 70 | + | |
| 71 | + function reset(cm) { | |
| 72 | + clear(cm); | |
| 73 | + var ranges = cm.listSelections(); | |
| 74 | + for (var i = 0; i < ranges.length; i++) | |
| 75 | + coverRange(cm, ranges[i].from(), ranges[i].to()); | |
| 76 | + } | |
| 77 | + | |
| 78 | + function update(cm) { | |
| 79 | + if (!cm.somethingSelected()) return clear(cm); | |
| 80 | + if (cm.listSelections().length > 1) return reset(cm); | |
| 81 | + | |
| 82 | + var from = cm.getCursor("start"), to = cm.getCursor("end"); | |
| 83 | + | |
| 84 | + var array = cm.state.markedSelection; | |
| 85 | + if (!array.length) return coverRange(cm, from, to); | |
| 86 | + | |
| 87 | + var coverStart = array[0].find(), coverEnd = array[array.length - 1].find(); | |
| 88 | + if (!coverStart || !coverEnd || to.line - from.line < CHUNK_SIZE || | |
| 89 | + cmp(from, coverEnd.to) >= 0 || cmp(to, coverStart.from) <= 0) | |
| 90 | + return reset(cm); | |
| 91 | + | |
| 92 | + while (cmp(from, coverStart.from) > 0) { | |
| 93 | + array.shift().clear(); | |
| 94 | + coverStart = array[0].find(); | |
| 95 | + } | |
| 96 | + if (cmp(from, coverStart.from) < 0) { | |
| 97 | + if (coverStart.to.line - from.line < CHUNK_SIZE) { | |
| 98 | + array.shift().clear(); | |
| 99 | + coverRange(cm, from, coverStart.to, 0); | |
| 100 | + } else { | |
| 101 | + coverRange(cm, from, coverStart.from, 0); | |
| 102 | + } | |
| 103 | + } | |
| 104 | + | |
| 105 | + while (cmp(to, coverEnd.to) < 0) { | |
| 106 | + array.pop().clear(); | |
| 107 | + coverEnd = array[array.length - 1].find(); | |
| 108 | + } | |
| 109 | + if (cmp(to, coverEnd.to) > 0) { | |
| 110 | + if (to.line - coverEnd.from.line < CHUNK_SIZE) { | |
| 111 | + array.pop().clear(); | |
| 112 | + coverRange(cm, coverEnd.from, to); | |
| 113 | + } else { | |
| 114 | + coverRange(cm, coverEnd.to, to); | |
| 115 | + } | |
| 116 | + } | |
| 117 | + } | |
| 118 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,86 @@ |
| 1 | +.CodeMirror-Tern-completion { | |
| 2 | + padding-left: 22px; | |
| 3 | + position: relative; | |
| 4 | +} | |
| 5 | +.CodeMirror-Tern-completion:before { | |
| 6 | + position: absolute; | |
| 7 | + left: 2px; | |
| 8 | + bottom: 2px; | |
| 9 | + border-radius: 50%; | |
| 10 | + font-size: 12px; | |
| 11 | + font-weight: bold; | |
| 12 | + height: 15px; | |
| 13 | + width: 15px; | |
| 14 | + line-height: 16px; | |
| 15 | + text-align: center; | |
| 16 | + color: white; | |
| 17 | + -moz-box-sizing: border-box; | |
| 18 | + box-sizing: border-box; | |
| 19 | +} | |
| 20 | +.CodeMirror-Tern-completion-unknown:before { | |
| 21 | + content: "?"; | |
| 22 | + background: #4bb; | |
| 23 | +} | |
| 24 | +.CodeMirror-Tern-completion-object:before { | |
| 25 | + content: "O"; | |
| 26 | + background: #77c; | |
| 27 | +} | |
| 28 | +.CodeMirror-Tern-completion-fn:before { | |
| 29 | + content: "F"; | |
| 30 | + background: #7c7; | |
| 31 | +} | |
| 32 | +.CodeMirror-Tern-completion-array:before { | |
| 33 | + content: "A"; | |
| 34 | + background: #c66; | |
| 35 | +} | |
| 36 | +.CodeMirror-Tern-completion-number:before { | |
| 37 | + content: "1"; | |
| 38 | + background: #999; | |
| 39 | +} | |
| 40 | +.CodeMirror-Tern-completion-string:before { | |
| 41 | + content: "S"; | |
| 42 | + background: #999; | |
| 43 | +} | |
| 44 | +.CodeMirror-Tern-completion-bool:before { | |
| 45 | + content: "B"; | |
| 46 | + background: #999; | |
| 47 | +} | |
| 48 | + | |
| 49 | +.CodeMirror-Tern-completion-guess { | |
| 50 | + color: #999; | |
| 51 | +} | |
| 52 | + | |
| 53 | +.CodeMirror-Tern-tooltip { | |
| 54 | + border: 1px solid silver; | |
| 55 | + border-radius: 3px; | |
| 56 | + color: #444; | |
| 57 | + padding: 2px 5px; | |
| 58 | + font-size: 90%; | |
| 59 | + font-family: monospace; | |
| 60 | + background-color: white; | |
| 61 | + white-space: pre-wrap; | |
| 62 | + | |
| 63 | + max-width: 40em; | |
| 64 | + position: absolute; | |
| 65 | + z-index: 10; | |
| 66 | + -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2); | |
| 67 | + -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); | |
| 68 | + box-shadow: 2px 3px 5px rgba(0,0,0,.2); | |
| 69 | + | |
| 70 | + transition: opacity 1s; | |
| 71 | + -moz-transition: opacity 1s; | |
| 72 | + -webkit-transition: opacity 1s; | |
| 73 | + -o-transition: opacity 1s; | |
| 74 | + -ms-transition: opacity 1s; | |
| 75 | +} | |
| 76 | + | |
| 77 | +.CodeMirror-Tern-hint-doc { | |
| 78 | + max-width: 25em; | |
| 79 | + margin-top: -3px; | |
| 80 | +} | |
| 81 | + | |
| 82 | +.CodeMirror-Tern-fname { color: black; } | |
| 83 | +.CodeMirror-Tern-farg { color: #70a; } | |
| 84 | +.CodeMirror-Tern-farg-current { text-decoration: underline; } | |
| 85 | +.CodeMirror-Tern-type { color: #07c; } | |
| 86 | +.CodeMirror-Tern-fhint-guess { opacity: .7; } | ... | ... |
| ... | ... | @@ -0,0 +1,668 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +// Glue code between CodeMirror and Tern. | |
| 5 | +// | |
| 6 | +// Create a CodeMirror.TernServer to wrap an actual Tern server, | |
| 7 | +// register open documents (CodeMirror.Doc instances) with it, and | |
| 8 | +// call its methods to activate the assisting functions that Tern | |
| 9 | +// provides. | |
| 10 | +// | |
| 11 | +// Options supported (all optional): | |
| 12 | +// * defs: An array of JSON definition data structures. | |
| 13 | +// * plugins: An object mapping plugin names to configuration | |
| 14 | +// options. | |
| 15 | +// * getFile: A function(name, c) that can be used to access files in | |
| 16 | +// the project that haven't been loaded yet. Simply do c(null) to | |
| 17 | +// indicate that a file is not available. | |
| 18 | +// * fileFilter: A function(value, docName, doc) that will be applied | |
| 19 | +// to documents before passing them on to Tern. | |
| 20 | +// * switchToDoc: A function(name, doc) that should, when providing a | |
| 21 | +// multi-file view, switch the view or focus to the named file. | |
| 22 | +// * showError: A function(editor, message) that can be used to | |
| 23 | +// override the way errors are displayed. | |
| 24 | +// * completionTip: Customize the content in tooltips for completions. | |
| 25 | +// Is passed a single argument—the completion's data as returned by | |
| 26 | +// Tern—and may return a string, DOM node, or null to indicate that | |
| 27 | +// no tip should be shown. By default the docstring is shown. | |
| 28 | +// * typeTip: Like completionTip, but for the tooltips shown for type | |
| 29 | +// queries. | |
| 30 | +// * responseFilter: A function(doc, query, request, error, data) that | |
| 31 | +// will be applied to the Tern responses before treating them | |
| 32 | +// | |
| 33 | +// | |
| 34 | +// It is possible to run the Tern server in a web worker by specifying | |
| 35 | +// these additional options: | |
| 36 | +// * useWorker: Set to true to enable web worker mode. You'll probably | |
| 37 | +// want to feature detect the actual value you use here, for example | |
| 38 | +// !!window.Worker. | |
| 39 | +// * workerScript: The main script of the worker. Point this to | |
| 40 | +// wherever you are hosting worker.js from this directory. | |
| 41 | +// * workerDeps: An array of paths pointing (relative to workerScript) | |
| 42 | +// to the Acorn and Tern libraries and any Tern plugins you want to | |
| 43 | +// load. Or, if you minified those into a single script and included | |
| 44 | +// them in the workerScript, simply leave this undefined. | |
| 45 | + | |
| 46 | +(function(mod) { | |
| 47 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 48 | + mod(require("../../lib/codemirror")); | |
| 49 | + else if (typeof define == "function" && define.amd) // AMD | |
| 50 | + define(["../../lib/codemirror"], mod); | |
| 51 | + else // Plain browser env | |
| 52 | + mod(CodeMirror); | |
| 53 | +})(function(CodeMirror) { | |
| 54 | + "use strict"; | |
| 55 | + // declare global: tern | |
| 56 | + | |
| 57 | + CodeMirror.TernServer = function(options) { | |
| 58 | + var self = this; | |
| 59 | + this.options = options || {}; | |
| 60 | + var plugins = this.options.plugins || (this.options.plugins = {}); | |
| 61 | + if (!plugins.doc_comment) plugins.doc_comment = true; | |
| 62 | + if (this.options.useWorker) { | |
| 63 | + this.server = new WorkerServer(this); | |
| 64 | + } else { | |
| 65 | + this.server = new tern.Server({ | |
| 66 | + getFile: function(name, c) { return getFile(self, name, c); }, | |
| 67 | + async: true, | |
| 68 | + defs: this.options.defs || [], | |
| 69 | + plugins: plugins | |
| 70 | + }); | |
| 71 | + } | |
| 72 | + this.docs = Object.create(null); | |
| 73 | + this.trackChange = function(doc, change) { trackChange(self, doc, change); }; | |
| 74 | + | |
| 75 | + this.cachedArgHints = null; | |
| 76 | + this.activeArgHints = null; | |
| 77 | + this.jumpStack = []; | |
| 78 | + | |
| 79 | + this.getHint = function(cm, c) { return hint(self, cm, c); }; | |
| 80 | + this.getHint.async = true; | |
| 81 | + }; | |
| 82 | + | |
| 83 | + CodeMirror.TernServer.prototype = { | |
| 84 | + addDoc: function(name, doc) { | |
| 85 | + var data = {doc: doc, name: name, changed: null}; | |
| 86 | + this.server.addFile(name, docValue(this, data)); | |
| 87 | + CodeMirror.on(doc, "change", this.trackChange); | |
| 88 | + return this.docs[name] = data; | |
| 89 | + }, | |
| 90 | + | |
| 91 | + delDoc: function(id) { | |
| 92 | + var found = resolveDoc(this, id); | |
| 93 | + if (!found) return; | |
| 94 | + CodeMirror.off(found.doc, "change", this.trackChange); | |
| 95 | + delete this.docs[found.name]; | |
| 96 | + this.server.delFile(found.name); | |
| 97 | + }, | |
| 98 | + | |
| 99 | + hideDoc: function(id) { | |
| 100 | + closeArgHints(this); | |
| 101 | + var found = resolveDoc(this, id); | |
| 102 | + if (found && found.changed) sendDoc(this, found); | |
| 103 | + }, | |
| 104 | + | |
| 105 | + complete: function(cm) { | |
| 106 | + cm.showHint({hint: this.getHint}); | |
| 107 | + }, | |
| 108 | + | |
| 109 | + showType: function(cm, pos, c) { showType(this, cm, pos, c); }, | |
| 110 | + | |
| 111 | + updateArgHints: function(cm) { updateArgHints(this, cm); }, | |
| 112 | + | |
| 113 | + jumpToDef: function(cm) { jumpToDef(this, cm); }, | |
| 114 | + | |
| 115 | + jumpBack: function(cm) { jumpBack(this, cm); }, | |
| 116 | + | |
| 117 | + rename: function(cm) { rename(this, cm); }, | |
| 118 | + | |
| 119 | + selectName: function(cm) { selectName(this, cm); }, | |
| 120 | + | |
| 121 | + request: function (cm, query, c, pos) { | |
| 122 | + var self = this; | |
| 123 | + var doc = findDoc(this, cm.getDoc()); | |
| 124 | + var request = buildRequest(this, doc, query, pos); | |
| 125 | + | |
| 126 | + this.server.request(request, function (error, data) { | |
| 127 | + if (!error && self.options.responseFilter) | |
| 128 | + data = self.options.responseFilter(doc, query, request, error, data); | |
| 129 | + c(error, data); | |
| 130 | + }); | |
| 131 | + } | |
| 132 | + }; | |
| 133 | + | |
| 134 | + var Pos = CodeMirror.Pos; | |
| 135 | + var cls = "CodeMirror-Tern-"; | |
| 136 | + var bigDoc = 250; | |
| 137 | + | |
| 138 | + function getFile(ts, name, c) { | |
| 139 | + var buf = ts.docs[name]; | |
| 140 | + if (buf) | |
| 141 | + c(docValue(ts, buf)); | |
| 142 | + else if (ts.options.getFile) | |
| 143 | + ts.options.getFile(name, c); | |
| 144 | + else | |
| 145 | + c(null); | |
| 146 | + } | |
| 147 | + | |
| 148 | + function findDoc(ts, doc, name) { | |
| 149 | + for (var n in ts.docs) { | |
| 150 | + var cur = ts.docs[n]; | |
| 151 | + if (cur.doc == doc) return cur; | |
| 152 | + } | |
| 153 | + if (!name) for (var i = 0;; ++i) { | |
| 154 | + n = "[doc" + (i || "") + "]"; | |
| 155 | + if (!ts.docs[n]) { name = n; break; } | |
| 156 | + } | |
| 157 | + return ts.addDoc(name, doc); | |
| 158 | + } | |
| 159 | + | |
| 160 | + function resolveDoc(ts, id) { | |
| 161 | + if (typeof id == "string") return ts.docs[id]; | |
| 162 | + if (id instanceof CodeMirror) id = id.getDoc(); | |
| 163 | + if (id instanceof CodeMirror.Doc) return findDoc(ts, id); | |
| 164 | + } | |
| 165 | + | |
| 166 | + function trackChange(ts, doc, change) { | |
| 167 | + var data = findDoc(ts, doc); | |
| 168 | + | |
| 169 | + var argHints = ts.cachedArgHints; | |
| 170 | + if (argHints && argHints.doc == doc && cmpPos(argHints.start, change.to) <= 0) | |
| 171 | + ts.cachedArgHints = null; | |
| 172 | + | |
| 173 | + var changed = data.changed; | |
| 174 | + if (changed == null) | |
| 175 | + data.changed = changed = {from: change.from.line, to: change.from.line}; | |
| 176 | + var end = change.from.line + (change.text.length - 1); | |
| 177 | + if (change.from.line < changed.to) changed.to = changed.to - (change.to.line - end); | |
| 178 | + if (end >= changed.to) changed.to = end + 1; | |
| 179 | + if (changed.from > change.from.line) changed.from = change.from.line; | |
| 180 | + | |
| 181 | + if (doc.lineCount() > bigDoc && change.to - changed.from > 100) setTimeout(function() { | |
| 182 | + if (data.changed && data.changed.to - data.changed.from > 100) sendDoc(ts, data); | |
| 183 | + }, 200); | |
| 184 | + } | |
| 185 | + | |
| 186 | + function sendDoc(ts, doc) { | |
| 187 | + ts.server.request({files: [{type: "full", name: doc.name, text: docValue(ts, doc)}]}, function(error) { | |
| 188 | + if (error) window.console.error(error); | |
| 189 | + else doc.changed = null; | |
| 190 | + }); | |
| 191 | + } | |
| 192 | + | |
| 193 | + // Completion | |
| 194 | + | |
| 195 | + function hint(ts, cm, c) { | |
| 196 | + ts.request(cm, {type: "completions", types: true, docs: true, urls: true}, function(error, data) { | |
| 197 | + if (error) return showError(ts, cm, error); | |
| 198 | + var completions = [], after = ""; | |
| 199 | + var from = data.start, to = data.end; | |
| 200 | + if (cm.getRange(Pos(from.line, from.ch - 2), from) == "[\"" && | |
| 201 | + cm.getRange(to, Pos(to.line, to.ch + 2)) != "\"]") | |
| 202 | + after = "\"]"; | |
| 203 | + | |
| 204 | + for (var i = 0; i < data.completions.length; ++i) { | |
| 205 | + var completion = data.completions[i], className = typeToIcon(completion.type); | |
| 206 | + if (data.guess) className += " " + cls + "guess"; | |
| 207 | + completions.push({text: completion.name + after, | |
| 208 | + displayText: completion.name, | |
| 209 | + className: className, | |
| 210 | + data: completion}); | |
| 211 | + } | |
| 212 | + | |
| 213 | + var obj = {from: from, to: to, list: completions}; | |
| 214 | + var tooltip = null; | |
| 215 | + CodeMirror.on(obj, "close", function() { remove(tooltip); }); | |
| 216 | + CodeMirror.on(obj, "update", function() { remove(tooltip); }); | |
| 217 | + CodeMirror.on(obj, "select", function(cur, node) { | |
| 218 | + remove(tooltip); | |
| 219 | + var content = ts.options.completionTip ? ts.options.completionTip(cur.data) : cur.data.doc; | |
| 220 | + if (content) { | |
| 221 | + tooltip = makeTooltip(node.parentNode.getBoundingClientRect().right + window.pageXOffset, | |
| 222 | + node.getBoundingClientRect().top + window.pageYOffset, content); | |
| 223 | + tooltip.className += " " + cls + "hint-doc"; | |
| 224 | + } | |
| 225 | + }); | |
| 226 | + c(obj); | |
| 227 | + }); | |
| 228 | + } | |
| 229 | + | |
| 230 | + function typeToIcon(type) { | |
| 231 | + var suffix; | |
| 232 | + if (type == "?") suffix = "unknown"; | |
| 233 | + else if (type == "number" || type == "string" || type == "bool") suffix = type; | |
| 234 | + else if (/^fn\(/.test(type)) suffix = "fn"; | |
| 235 | + else if (/^\[/.test(type)) suffix = "array"; | |
| 236 | + else suffix = "object"; | |
| 237 | + return cls + "completion " + cls + "completion-" + suffix; | |
| 238 | + } | |
| 239 | + | |
| 240 | + // Type queries | |
| 241 | + | |
| 242 | + function showType(ts, cm, pos, c) { | |
| 243 | + ts.request(cm, "type", function(error, data) { | |
| 244 | + if (error) return showError(ts, cm, error); | |
| 245 | + if (ts.options.typeTip) { | |
| 246 | + var tip = ts.options.typeTip(data); | |
| 247 | + } else { | |
| 248 | + var tip = elt("span", null, elt("strong", null, data.type || "not found")); | |
| 249 | + if (data.doc) | |
| 250 | + tip.appendChild(document.createTextNode(" — " + data.doc)); | |
| 251 | + if (data.url) { | |
| 252 | + tip.appendChild(document.createTextNode(" ")); | |
| 253 | + tip.appendChild(elt("a", null, "[docs]")).href = data.url; | |
| 254 | + } | |
| 255 | + } | |
| 256 | + tempTooltip(cm, tip); | |
| 257 | + if (c) c(); | |
| 258 | + }, pos); | |
| 259 | + } | |
| 260 | + | |
| 261 | + // Maintaining argument hints | |
| 262 | + | |
| 263 | + function updateArgHints(ts, cm) { | |
| 264 | + closeArgHints(ts); | |
| 265 | + | |
| 266 | + if (cm.somethingSelected()) return; | |
| 267 | + var state = cm.getTokenAt(cm.getCursor()).state; | |
| 268 | + var inner = CodeMirror.innerMode(cm.getMode(), state); | |
| 269 | + if (inner.mode.name != "javascript") return; | |
| 270 | + var lex = inner.state.lexical; | |
| 271 | + if (lex.info != "call") return; | |
| 272 | + | |
| 273 | + var ch, argPos = lex.pos || 0, tabSize = cm.getOption("tabSize"); | |
| 274 | + for (var line = cm.getCursor().line, e = Math.max(0, line - 9), found = false; line >= e; --line) { | |
| 275 | + var str = cm.getLine(line), extra = 0; | |
| 276 | + for (var pos = 0;;) { | |
| 277 | + var tab = str.indexOf("\t", pos); | |
| 278 | + if (tab == -1) break; | |
| 279 | + extra += tabSize - (tab + extra) % tabSize - 1; | |
| 280 | + pos = tab + 1; | |
| 281 | + } | |
| 282 | + ch = lex.column - extra; | |
| 283 | + if (str.charAt(ch) == "(") {found = true; break;} | |
| 284 | + } | |
| 285 | + if (!found) return; | |
| 286 | + | |
| 287 | + var start = Pos(line, ch); | |
| 288 | + var cache = ts.cachedArgHints; | |
| 289 | + if (cache && cache.doc == cm.getDoc() && cmpPos(start, cache.start) == 0) | |
| 290 | + return showArgHints(ts, cm, argPos); | |
| 291 | + | |
| 292 | + ts.request(cm, {type: "type", preferFunction: true, end: start}, function(error, data) { | |
| 293 | + if (error || !data.type || !(/^fn\(/).test(data.type)) return; | |
| 294 | + ts.cachedArgHints = { | |
| 295 | + start: pos, | |
| 296 | + type: parseFnType(data.type), | |
| 297 | + name: data.exprName || data.name || "fn", | |
| 298 | + guess: data.guess, | |
| 299 | + doc: cm.getDoc() | |
| 300 | + }; | |
| 301 | + showArgHints(ts, cm, argPos); | |
| 302 | + }); | |
| 303 | + } | |
| 304 | + | |
| 305 | + function showArgHints(ts, cm, pos) { | |
| 306 | + closeArgHints(ts); | |
| 307 | + | |
| 308 | + var cache = ts.cachedArgHints, tp = cache.type; | |
| 309 | + var tip = elt("span", cache.guess ? cls + "fhint-guess" : null, | |
| 310 | + elt("span", cls + "fname", cache.name), "("); | |
| 311 | + for (var i = 0; i < tp.args.length; ++i) { | |
| 312 | + if (i) tip.appendChild(document.createTextNode(", ")); | |
| 313 | + var arg = tp.args[i]; | |
| 314 | + tip.appendChild(elt("span", cls + "farg" + (i == pos ? " " + cls + "farg-current" : ""), arg.name || "?")); | |
| 315 | + if (arg.type != "?") { | |
| 316 | + tip.appendChild(document.createTextNode(":\u00a0")); | |
| 317 | + tip.appendChild(elt("span", cls + "type", arg.type)); | |
| 318 | + } | |
| 319 | + } | |
| 320 | + tip.appendChild(document.createTextNode(tp.rettype ? ") ->\u00a0" : ")")); | |
| 321 | + if (tp.rettype) tip.appendChild(elt("span", cls + "type", tp.rettype)); | |
| 322 | + var place = cm.cursorCoords(null, "page"); | |
| 323 | + ts.activeArgHints = makeTooltip(place.right + 1, place.bottom, tip); | |
| 324 | + } | |
| 325 | + | |
| 326 | + function parseFnType(text) { | |
| 327 | + var args = [], pos = 3; | |
| 328 | + | |
| 329 | + function skipMatching(upto) { | |
| 330 | + var depth = 0, start = pos; | |
| 331 | + for (;;) { | |
| 332 | + var next = text.charAt(pos); | |
| 333 | + if (upto.test(next) && !depth) return text.slice(start, pos); | |
| 334 | + if (/[{\[\(]/.test(next)) ++depth; | |
| 335 | + else if (/[}\]\)]/.test(next)) --depth; | |
| 336 | + ++pos; | |
| 337 | + } | |
| 338 | + } | |
| 339 | + | |
| 340 | + // Parse arguments | |
| 341 | + if (text.charAt(pos) != ")") for (;;) { | |
| 342 | + var name = text.slice(pos).match(/^([^, \(\[\{]+): /); | |
| 343 | + if (name) { | |
| 344 | + pos += name[0].length; | |
| 345 | + name = name[1]; | |
| 346 | + } | |
| 347 | + args.push({name: name, type: skipMatching(/[\),]/)}); | |
| 348 | + if (text.charAt(pos) == ")") break; | |
| 349 | + pos += 2; | |
| 350 | + } | |
| 351 | + | |
| 352 | + var rettype = text.slice(pos).match(/^\) -> (.*)$/); | |
| 353 | + | |
| 354 | + return {args: args, rettype: rettype && rettype[1]}; | |
| 355 | + } | |
| 356 | + | |
| 357 | + // Moving to the definition of something | |
| 358 | + | |
| 359 | + function jumpToDef(ts, cm) { | |
| 360 | + function inner(varName) { | |
| 361 | + var req = {type: "definition", variable: varName || null}; | |
| 362 | + var doc = findDoc(ts, cm.getDoc()); | |
| 363 | + ts.server.request(buildRequest(ts, doc, req), function(error, data) { | |
| 364 | + if (error) return showError(ts, cm, error); | |
| 365 | + if (!data.file && data.url) { window.open(data.url); return; } | |
| 366 | + | |
| 367 | + if (data.file) { | |
| 368 | + var localDoc = ts.docs[data.file], found; | |
| 369 | + if (localDoc && (found = findContext(localDoc.doc, data))) { | |
| 370 | + ts.jumpStack.push({file: doc.name, | |
| 371 | + start: cm.getCursor("from"), | |
| 372 | + end: cm.getCursor("to")}); | |
| 373 | + moveTo(ts, doc, localDoc, found.start, found.end); | |
| 374 | + return; | |
| 375 | + } | |
| 376 | + } | |
| 377 | + showError(ts, cm, "Could not find a definition."); | |
| 378 | + }); | |
| 379 | + } | |
| 380 | + | |
| 381 | + if (!atInterestingExpression(cm)) | |
| 382 | + dialog(cm, "Jump to variable", function(name) { if (name) inner(name); }); | |
| 383 | + else | |
| 384 | + inner(); | |
| 385 | + } | |
| 386 | + | |
| 387 | + function jumpBack(ts, cm) { | |
| 388 | + var pos = ts.jumpStack.pop(), doc = pos && ts.docs[pos.file]; | |
| 389 | + if (!doc) return; | |
| 390 | + moveTo(ts, findDoc(ts, cm.getDoc()), doc, pos.start, pos.end); | |
| 391 | + } | |
| 392 | + | |
| 393 | + function moveTo(ts, curDoc, doc, start, end) { | |
| 394 | + doc.doc.setSelection(start, end); | |
| 395 | + if (curDoc != doc && ts.options.switchToDoc) { | |
| 396 | + closeArgHints(ts); | |
| 397 | + ts.options.switchToDoc(doc.name, doc.doc); | |
| 398 | + } | |
| 399 | + } | |
| 400 | + | |
| 401 | + // The {line,ch} representation of positions makes this rather awkward. | |
| 402 | + function findContext(doc, data) { | |
| 403 | + var before = data.context.slice(0, data.contextOffset).split("\n"); | |
| 404 | + var startLine = data.start.line - (before.length - 1); | |
| 405 | + var start = Pos(startLine, (before.length == 1 ? data.start.ch : doc.getLine(startLine).length) - before[0].length); | |
| 406 | + | |
| 407 | + var text = doc.getLine(startLine).slice(start.ch); | |
| 408 | + for (var cur = startLine + 1; cur < doc.lineCount() && text.length < data.context.length; ++cur) | |
| 409 | + text += "\n" + doc.getLine(cur); | |
| 410 | + if (text.slice(0, data.context.length) == data.context) return data; | |
| 411 | + | |
| 412 | + var cursor = doc.getSearchCursor(data.context, 0, false); | |
| 413 | + var nearest, nearestDist = Infinity; | |
| 414 | + while (cursor.findNext()) { | |
| 415 | + var from = cursor.from(), dist = Math.abs(from.line - start.line) * 10000; | |
| 416 | + if (!dist) dist = Math.abs(from.ch - start.ch); | |
| 417 | + if (dist < nearestDist) { nearest = from; nearestDist = dist; } | |
| 418 | + } | |
| 419 | + if (!nearest) return null; | |
| 420 | + | |
| 421 | + if (before.length == 1) | |
| 422 | + nearest.ch += before[0].length; | |
| 423 | + else | |
| 424 | + nearest = Pos(nearest.line + (before.length - 1), before[before.length - 1].length); | |
| 425 | + if (data.start.line == data.end.line) | |
| 426 | + var end = Pos(nearest.line, nearest.ch + (data.end.ch - data.start.ch)); | |
| 427 | + else | |
| 428 | + var end = Pos(nearest.line + (data.end.line - data.start.line), data.end.ch); | |
| 429 | + return {start: nearest, end: end}; | |
| 430 | + } | |
| 431 | + | |
| 432 | + function atInterestingExpression(cm) { | |
| 433 | + var pos = cm.getCursor("end"), tok = cm.getTokenAt(pos); | |
| 434 | + if (tok.start < pos.ch && (tok.type == "comment" || tok.type == "string")) return false; | |
| 435 | + return /\w/.test(cm.getLine(pos.line).slice(Math.max(pos.ch - 1, 0), pos.ch + 1)); | |
| 436 | + } | |
| 437 | + | |
| 438 | + // Variable renaming | |
| 439 | + | |
| 440 | + function rename(ts, cm) { | |
| 441 | + var token = cm.getTokenAt(cm.getCursor()); | |
| 442 | + if (!/\w/.test(token.string)) return showError(ts, cm, "Not at a variable"); | |
| 443 | + dialog(cm, "New name for " + token.string, function(newName) { | |
| 444 | + ts.request(cm, {type: "rename", newName: newName, fullDocs: true}, function(error, data) { | |
| 445 | + if (error) return showError(ts, cm, error); | |
| 446 | + applyChanges(ts, data.changes); | |
| 447 | + }); | |
| 448 | + }); | |
| 449 | + } | |
| 450 | + | |
| 451 | + function selectName(ts, cm) { | |
| 452 | + var name = findDoc(ts, cm.doc).name; | |
| 453 | + ts.request(cm, {type: "refs"}, function(error, data) { | |
| 454 | + if (error) return showError(ts, cm, error); | |
| 455 | + var ranges = [], cur = 0; | |
| 456 | + for (var i = 0; i < data.refs.length; i++) { | |
| 457 | + var ref = data.refs[i]; | |
| 458 | + if (ref.file == name) { | |
| 459 | + ranges.push({anchor: ref.start, head: ref.end}); | |
| 460 | + if (cmpPos(cur, ref.start) >= 0 && cmpPos(cur, ref.end) <= 0) | |
| 461 | + cur = ranges.length - 1; | |
| 462 | + } | |
| 463 | + } | |
| 464 | + cm.setSelections(ranges, cur); | |
| 465 | + }); | |
| 466 | + } | |
| 467 | + | |
| 468 | + var nextChangeOrig = 0; | |
| 469 | + function applyChanges(ts, changes) { | |
| 470 | + var perFile = Object.create(null); | |
| 471 | + for (var i = 0; i < changes.length; ++i) { | |
| 472 | + var ch = changes[i]; | |
| 473 | + (perFile[ch.file] || (perFile[ch.file] = [])).push(ch); | |
| 474 | + } | |
| 475 | + for (var file in perFile) { | |
| 476 | + var known = ts.docs[file], chs = perFile[file];; | |
| 477 | + if (!known) continue; | |
| 478 | + chs.sort(function(a, b) { return cmpPos(b.start, a.start); }); | |
| 479 | + var origin = "*rename" + (++nextChangeOrig); | |
| 480 | + for (var i = 0; i < chs.length; ++i) { | |
| 481 | + var ch = chs[i]; | |
| 482 | + known.doc.replaceRange(ch.text, ch.start, ch.end, origin); | |
| 483 | + } | |
| 484 | + } | |
| 485 | + } | |
| 486 | + | |
| 487 | + // Generic request-building helper | |
| 488 | + | |
| 489 | + function buildRequest(ts, doc, query, pos) { | |
| 490 | + var files = [], offsetLines = 0, allowFragments = !query.fullDocs; | |
| 491 | + if (!allowFragments) delete query.fullDocs; | |
| 492 | + if (typeof query == "string") query = {type: query}; | |
| 493 | + query.lineCharPositions = true; | |
| 494 | + if (query.end == null) { | |
| 495 | + query.end = pos || doc.doc.getCursor("end"); | |
| 496 | + if (doc.doc.somethingSelected()) | |
| 497 | + query.start = doc.doc.getCursor("start"); | |
| 498 | + } | |
| 499 | + var startPos = query.start || query.end; | |
| 500 | + | |
| 501 | + if (doc.changed) { | |
| 502 | + if (doc.doc.lineCount() > bigDoc && allowFragments !== false && | |
| 503 | + doc.changed.to - doc.changed.from < 100 && | |
| 504 | + doc.changed.from <= startPos.line && doc.changed.to > query.end.line) { | |
| 505 | + files.push(getFragmentAround(doc, startPos, query.end)); | |
| 506 | + query.file = "#0"; | |
| 507 | + var offsetLines = files[0].offsetLines; | |
| 508 | + if (query.start != null) query.start = Pos(query.start.line - -offsetLines, query.start.ch); | |
| 509 | + query.end = Pos(query.end.line - offsetLines, query.end.ch); | |
| 510 | + } else { | |
| 511 | + files.push({type: "full", | |
| 512 | + name: doc.name, | |
| 513 | + text: docValue(ts, doc)}); | |
| 514 | + query.file = doc.name; | |
| 515 | + doc.changed = null; | |
| 516 | + } | |
| 517 | + } else { | |
| 518 | + query.file = doc.name; | |
| 519 | + } | |
| 520 | + for (var name in ts.docs) { | |
| 521 | + var cur = ts.docs[name]; | |
| 522 | + if (cur.changed && cur != doc) { | |
| 523 | + files.push({type: "full", name: cur.name, text: docValue(ts, cur)}); | |
| 524 | + cur.changed = null; | |
| 525 | + } | |
| 526 | + } | |
| 527 | + | |
| 528 | + return {query: query, files: files}; | |
| 529 | + } | |
| 530 | + | |
| 531 | + function getFragmentAround(data, start, end) { | |
| 532 | + var doc = data.doc; | |
| 533 | + var minIndent = null, minLine = null, endLine, tabSize = 4; | |
| 534 | + for (var p = start.line - 1, min = Math.max(0, p - 50); p >= min; --p) { | |
| 535 | + var line = doc.getLine(p), fn = line.search(/\bfunction\b/); | |
| 536 | + if (fn < 0) continue; | |
| 537 | + var indent = CodeMirror.countColumn(line, null, tabSize); | |
| 538 | + if (minIndent != null && minIndent <= indent) continue; | |
| 539 | + minIndent = indent; | |
| 540 | + minLine = p; | |
| 541 | + } | |
| 542 | + if (minLine == null) minLine = min; | |
| 543 | + var max = Math.min(doc.lastLine(), end.line + 20); | |
| 544 | + if (minIndent == null || minIndent == CodeMirror.countColumn(doc.getLine(start.line), null, tabSize)) | |
| 545 | + endLine = max; | |
| 546 | + else for (endLine = end.line + 1; endLine < max; ++endLine) { | |
| 547 | + var indent = CodeMirror.countColumn(doc.getLine(endLine), null, tabSize); | |
| 548 | + if (indent <= minIndent) break; | |
| 549 | + } | |
| 550 | + var from = Pos(minLine, 0); | |
| 551 | + | |
| 552 | + return {type: "part", | |
| 553 | + name: data.name, | |
| 554 | + offsetLines: from.line, | |
| 555 | + text: doc.getRange(from, Pos(endLine, 0))}; | |
| 556 | + } | |
| 557 | + | |
| 558 | + // Generic utilities | |
| 559 | + | |
| 560 | + var cmpPos = CodeMirror.cmpPos; | |
| 561 | + | |
| 562 | + function elt(tagname, cls /*, ... elts*/) { | |
| 563 | + var e = document.createElement(tagname); | |
| 564 | + if (cls) e.className = cls; | |
| 565 | + for (var i = 2; i < arguments.length; ++i) { | |
| 566 | + var elt = arguments[i]; | |
| 567 | + if (typeof elt == "string") elt = document.createTextNode(elt); | |
| 568 | + e.appendChild(elt); | |
| 569 | + } | |
| 570 | + return e; | |
| 571 | + } | |
| 572 | + | |
| 573 | + function dialog(cm, text, f) { | |
| 574 | + if (cm.openDialog) | |
| 575 | + cm.openDialog(text + ": <input type=text>", f); | |
| 576 | + else | |
| 577 | + f(prompt(text, "")); | |
| 578 | + } | |
| 579 | + | |
| 580 | + // Tooltips | |
| 581 | + | |
| 582 | + function tempTooltip(cm, content) { | |
| 583 | + var where = cm.cursorCoords(); | |
| 584 | + var tip = makeTooltip(where.right + 1, where.bottom, content); | |
| 585 | + function clear() { | |
| 586 | + if (!tip.parentNode) return; | |
| 587 | + cm.off("cursorActivity", clear); | |
| 588 | + fadeOut(tip); | |
| 589 | + } | |
| 590 | + setTimeout(clear, 1700); | |
| 591 | + cm.on("cursorActivity", clear); | |
| 592 | + } | |
| 593 | + | |
| 594 | + function makeTooltip(x, y, content) { | |
| 595 | + var node = elt("div", cls + "tooltip", content); | |
| 596 | + node.style.left = x + "px"; | |
| 597 | + node.style.top = y + "px"; | |
| 598 | + document.body.appendChild(node); | |
| 599 | + return node; | |
| 600 | + } | |
| 601 | + | |
| 602 | + function remove(node) { | |
| 603 | + var p = node && node.parentNode; | |
| 604 | + if (p) p.removeChild(node); | |
| 605 | + } | |
| 606 | + | |
| 607 | + function fadeOut(tooltip) { | |
| 608 | + tooltip.style.opacity = "0"; | |
| 609 | + setTimeout(function() { remove(tooltip); }, 1100); | |
| 610 | + } | |
| 611 | + | |
| 612 | + function showError(ts, cm, msg) { | |
| 613 | + if (ts.options.showError) | |
| 614 | + ts.options.showError(cm, msg); | |
| 615 | + else | |
| 616 | + tempTooltip(cm, String(msg)); | |
| 617 | + } | |
| 618 | + | |
| 619 | + function closeArgHints(ts) { | |
| 620 | + if (ts.activeArgHints) { remove(ts.activeArgHints); ts.activeArgHints = null; } | |
| 621 | + } | |
| 622 | + | |
| 623 | + function docValue(ts, doc) { | |
| 624 | + var val = doc.doc.getValue(); | |
| 625 | + if (ts.options.fileFilter) val = ts.options.fileFilter(val, doc.name, doc.doc); | |
| 626 | + return val; | |
| 627 | + } | |
| 628 | + | |
| 629 | + // Worker wrapper | |
| 630 | + | |
| 631 | + function WorkerServer(ts) { | |
| 632 | + var worker = new Worker(ts.options.workerScript); | |
| 633 | + worker.postMessage({type: "init", | |
| 634 | + defs: ts.options.defs, | |
| 635 | + plugins: ts.options.plugins, | |
| 636 | + scripts: ts.options.workerDeps}); | |
| 637 | + var msgId = 0, pending = {}; | |
| 638 | + | |
| 639 | + function send(data, c) { | |
| 640 | + if (c) { | |
| 641 | + data.id = ++msgId; | |
| 642 | + pending[msgId] = c; | |
| 643 | + } | |
| 644 | + worker.postMessage(data); | |
| 645 | + } | |
| 646 | + worker.onmessage = function(e) { | |
| 647 | + var data = e.data; | |
| 648 | + if (data.type == "getFile") { | |
| 649 | + getFile(ts, data.name, function(err, text) { | |
| 650 | + send({type: "getFile", err: String(err), text: text, id: data.id}); | |
| 651 | + }); | |
| 652 | + } else if (data.type == "debug") { | |
| 653 | + window.console.log(data.message); | |
| 654 | + } else if (data.id && pending[data.id]) { | |
| 655 | + pending[data.id](data.err, data.body); | |
| 656 | + delete pending[data.id]; | |
| 657 | + } | |
| 658 | + }; | |
| 659 | + worker.onerror = function(e) { | |
| 660 | + for (var id in pending) pending[id](e); | |
| 661 | + pending = {}; | |
| 662 | + }; | |
| 663 | + | |
| 664 | + this.addFile = function(name, text) { send({type: "add", name: name, text: text}); }; | |
| 665 | + this.delFile = function(name) { send({type: "del", name: name}); }; | |
| 666 | + this.request = function(body, c) { send({type: "req", body: body}, c); }; | |
| 667 | + } | |
| 668 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,44 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +// declare global: tern, server | |
| 5 | + | |
| 6 | +var server; | |
| 7 | + | |
| 8 | +this.onmessage = function(e) { | |
| 9 | + var data = e.data; | |
| 10 | + switch (data.type) { | |
| 11 | + case "init": return startServer(data.defs, data.plugins, data.scripts); | |
| 12 | + case "add": return server.addFile(data.name, data.text); | |
| 13 | + case "del": return server.delFile(data.name); | |
| 14 | + case "req": return server.request(data.body, function(err, reqData) { | |
| 15 | + postMessage({id: data.id, body: reqData, err: err && String(err)}); | |
| 16 | + }); | |
| 17 | + case "getFile": | |
| 18 | + var c = pending[data.id]; | |
| 19 | + delete pending[data.id]; | |
| 20 | + return c(data.err, data.text); | |
| 21 | + default: throw new Error("Unknown message type: " + data.type); | |
| 22 | + } | |
| 23 | +}; | |
| 24 | + | |
| 25 | +var nextId = 0, pending = {}; | |
| 26 | +function getFile(file, c) { | |
| 27 | + postMessage({type: "getFile", name: file, id: ++nextId}); | |
| 28 | + pending[nextId] = c; | |
| 29 | +} | |
| 30 | + | |
| 31 | +function startServer(defs, plugins, scripts) { | |
| 32 | + if (scripts) importScripts.apply(null, scripts); | |
| 33 | + | |
| 34 | + server = new tern.Server({ | |
| 35 | + getFile: getFile, | |
| 36 | + async: true, | |
| 37 | + defs: defs, | |
| 38 | + plugins: plugins | |
| 39 | + }); | |
| 40 | +} | |
| 41 | + | |
| 42 | +var console = { | |
| 43 | + log: function(v) { postMessage({type: "debug", message: v}); } | |
| 44 | +}; | ... | ... |
| ... | ... | @@ -0,0 +1,139 @@ |
| 1 | +// CodeMirror, copyright (c) by Marijn Haverbeke and others | |
| 2 | +// Distributed under an MIT license: http://codemirror.net/LICENSE | |
| 3 | + | |
| 4 | +(function(mod) { | |
| 5 | + if (typeof exports == "object" && typeof module == "object") // CommonJS | |
| 6 | + mod(require("../../lib/codemirror")); | |
| 7 | + else if (typeof define == "function" && define.amd) // AMD | |
| 8 | + define(["../../lib/codemirror"], mod); | |
| 9 | + else // Plain browser env | |
| 10 | + mod(CodeMirror); | |
| 11 | +})(function(CodeMirror) { | |
| 12 | + "use strict"; | |
| 13 | + | |
| 14 | + var Pos = CodeMirror.Pos; | |
| 15 | + | |
| 16 | + function findParagraph(cm, pos, options) { | |
| 17 | + var startRE = options.paragraphStart || cm.getHelper(pos, "paragraphStart"); | |
| 18 | + for (var start = pos.line, first = cm.firstLine(); start > first; --start) { | |
| 19 | + var line = cm.getLine(start); | |
| 20 | + if (startRE && startRE.test(line)) break; | |
| 21 | + if (!/\S/.test(line)) { ++start; break; } | |
| 22 | + } | |
| 23 | + var endRE = options.paragraphEnd || cm.getHelper(pos, "paragraphEnd"); | |
| 24 | + for (var end = pos.line + 1, last = cm.lastLine(); end <= last; ++end) { | |
| 25 | + var line = cm.getLine(end); | |
| 26 | + if (endRE && endRE.test(line)) { ++end; break; } | |
| 27 | + if (!/\S/.test(line)) break; | |
| 28 | + } | |
| 29 | + return {from: start, to: end}; | |
| 30 | + } | |
| 31 | + | |
| 32 | + function findBreakPoint(text, column, wrapOn, killTrailingSpace) { | |
| 33 | + for (var at = column; at > 0; --at) | |
| 34 | + if (wrapOn.test(text.slice(at - 1, at + 1))) break; | |
| 35 | + if (at == 0) at = column; | |
| 36 | + var endOfText = at; | |
| 37 | + if (killTrailingSpace) | |
| 38 | + while (text.charAt(endOfText - 1) == " ") --endOfText; | |
| 39 | + return {from: endOfText, to: at}; | |
| 40 | + } | |
| 41 | + | |
| 42 | + function wrapRange(cm, from, to, options) { | |
| 43 | + from = cm.clipPos(from); to = cm.clipPos(to); | |
| 44 | + var column = options.column || 80; | |
| 45 | + var wrapOn = options.wrapOn || /\s\S|-[^\.\d]/; | |
| 46 | + var killTrailing = options.killTrailingSpace !== false; | |
| 47 | + var changes = [], curLine = "", curNo = from.line; | |
| 48 | + var lines = cm.getRange(from, to, false); | |
| 49 | + if (!lines.length) return null; | |
| 50 | + var leadingSpace = lines[0].match(/^[ \t]*/)[0]; | |
| 51 | + | |
| 52 | + for (var i = 0; i < lines.length; ++i) { | |
| 53 | + var text = lines[i], oldLen = curLine.length, spaceInserted = 0; | |
| 54 | + if (curLine && text && !wrapOn.test(curLine.charAt(curLine.length - 1) + text.charAt(0))) { | |
| 55 | + curLine += " "; | |
| 56 | + spaceInserted = 1; | |
| 57 | + } | |
| 58 | + var spaceTrimmed = ""; | |
| 59 | + if (i) { | |
| 60 | + spaceTrimmed = text.match(/^\s*/)[0]; | |
| 61 | + text = text.slice(spaceTrimmed.length); | |
| 62 | + } | |
| 63 | + curLine += text; | |
| 64 | + if (i) { | |
| 65 | + var firstBreak = curLine.length > column && leadingSpace == spaceTrimmed && | |
| 66 | + findBreakPoint(curLine, column, wrapOn, killTrailing); | |
| 67 | + // If this isn't broken, or is broken at a different point, remove old break | |
| 68 | + if (!firstBreak || firstBreak.from != oldLen || firstBreak.to != oldLen + spaceInserted) { | |
| 69 | + changes.push({text: [spaceInserted ? " " : ""], | |
| 70 | + from: Pos(curNo, oldLen), | |
| 71 | + to: Pos(curNo + 1, spaceTrimmed.length)}); | |
| 72 | + } else { | |
| 73 | + curLine = leadingSpace + text; | |
| 74 | + ++curNo; | |
| 75 | + } | |
| 76 | + } | |
| 77 | + while (curLine.length > column) { | |
| 78 | + var bp = findBreakPoint(curLine, column, wrapOn, killTrailing); | |
| 79 | + changes.push({text: ["", leadingSpace], | |
| 80 | + from: Pos(curNo, bp.from), | |
| 81 | + to: Pos(curNo, bp.to)}); | |
| 82 | + curLine = leadingSpace + curLine.slice(bp.to); | |
| 83 | + ++curNo; | |
| 84 | + } | |
| 85 | + } | |
| 86 | + if (changes.length) cm.operation(function() { | |
| 87 | + for (var i = 0; i < changes.length; ++i) { | |
| 88 | + var change = changes[i]; | |
| 89 | + cm.replaceRange(change.text, change.from, change.to); | |
| 90 | + } | |
| 91 | + }); | |
| 92 | + return changes.length ? {from: changes[0].from, to: CodeMirror.changeEnd(changes[changes.length - 1])} : null; | |
| 93 | + } | |
| 94 | + | |
| 95 | + CodeMirror.defineExtension("wrapParagraph", function(pos, options) { | |
| 96 | + options = options || {}; | |
| 97 | + if (!pos) pos = this.getCursor(); | |
| 98 | + var para = findParagraph(this, pos, options); | |
| 99 | + return wrapRange(this, Pos(para.from, 0), Pos(para.to - 1), options); | |
| 100 | + }); | |
| 101 | + | |
| 102 | + CodeMirror.commands.wrapLines = function(cm) { | |
| 103 | + cm.operation(function() { | |
| 104 | + var ranges = cm.listSelections(), at = cm.lastLine() + 1; | |
| 105 | + for (var i = ranges.length - 1; i >= 0; i--) { | |
| 106 | + var range = ranges[i], span; | |
| 107 | + if (range.empty()) { | |
| 108 | + var para = findParagraph(cm, range.head, {}); | |
| 109 | + span = {from: Pos(para.from, 0), to: Pos(para.to - 1)}; | |
| 110 | + } else { | |
| 111 | + span = {from: range.from(), to: range.to()}; | |
| 112 | + } | |
| 113 | + if (span.to.line >= at) continue; | |
| 114 | + at = span.from.line; | |
| 115 | + wrapRange(cm, span.from, span.to, {}); | |
| 116 | + } | |
| 117 | + }); | |
| 118 | + }; | |
| 119 | + | |
| 120 | + CodeMirror.defineExtension("wrapRange", function(from, to, options) { | |
| 121 | + return wrapRange(this, from, to, options || {}); | |
| 122 | + }); | |
| 123 | + | |
| 124 | + CodeMirror.defineExtension("wrapParagraphsInRange", function(from, to, options) { | |
| 125 | + options = options || {}; | |
| 126 | + var cm = this, paras = []; | |
| 127 | + for (var line = from.line; line <= to.line;) { | |
| 128 | + var para = findParagraph(cm, Pos(line, 0), options); | |
| 129 | + paras.push(para); | |
| 130 | + line = para.to; | |
| 131 | + } | |
| 132 | + var madeChange = false; | |
| 133 | + if (paras.length) cm.operation(function() { | |
| 134 | + for (var i = paras.length - 1; i >= 0; --i) | |
| 135 | + madeChange = madeChange || wrapRange(cm, Pos(paras[i].from, 0), Pos(paras[i].to - 1), options); | |
| 136 | + }); | |
| 137 | + return madeChange; | |
| 138 | + }); | |
| 139 | +}); | ... | ... |
| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | +{ | |
| 2 | + "name": "codemirror", | |
| 3 | + "version":"4.6.0", | |
| 4 | + "main": ["lib/codemirror.js", "lib/codemirror.css"], | |
| 5 | + "ignore": [ | |
| 6 | + "**/.*", | |
| 7 | + "node_modules", | |
| 8 | + "components", | |
| 9 | + "bin", | |
| 10 | + "demo", | |
| 11 | + "doc", | |
| 12 | + "test", | |
| 13 | + "index.html", | |
| 14 | + "package.json" | |
| 15 | + ] | |
| 16 | +} | ... | ... |
| ... | ... | @@ -0,0 +1,78 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Active Line Demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<script src="../lib/codemirror.js"></script> | |
| 9 | +<script src="../mode/xml/xml.js"></script> | |
| 10 | +<script src="../addon/selection/active-line.js"></script> | |
| 11 | +<style type="text/css"> | |
| 12 | + .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;} | |
| 13 | + </style> | |
| 14 | +<div id=nav> | |
| 15 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 16 | + | |
| 17 | + <ul> | |
| 18 | + <li><a href="../index.html">Home</a> | |
| 19 | + <li><a href="../doc/manual.html">Manual</a> | |
| 20 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 21 | + </ul> | |
| 22 | + <ul> | |
| 23 | + <li><a class=active href="#">Active Line</a> | |
| 24 | + </ul> | |
| 25 | +</div> | |
| 26 | + | |
| 27 | +<article> | |
| 28 | +<h2>Active Line Demo</h2> | |
| 29 | +<form><textarea id="code" name="code"> | |
| 30 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 31 | +<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" | |
| 32 | + xmlns:georss="http://www.georss.org/georss" | |
| 33 | + xmlns:twitter="http://api.twitter.com"> | |
| 34 | + <channel> | |
| 35 | + <title>Twitter / codemirror</title> | |
| 36 | + <link>http://twitter.com/codemirror</link> | |
| 37 | + <atom:link type="application/rss+xml" | |
| 38 | + href="http://twitter.com/statuses/user_timeline/242283288.rss" rel="self"/> | |
| 39 | + <description>Twitter updates from CodeMirror / codemirror.</description> | |
| 40 | + <language>en-us</language> | |
| 41 | + <ttl>40</ttl> | |
| 42 | + <item> | |
| 43 | + <title>codemirror: http://cloud-ide.com — they're springing up like mushrooms. This one | |
| 44 | + uses CodeMirror as its editor.</title> | |
| 45 | + <description>codemirror: http://cloud-ide.com — they're springing up like mushrooms. This | |
| 46 | + one uses CodeMirror as its editor.</description> | |
| 47 | + <pubDate>Thu, 17 Mar 2011 23:34:47 +0000</pubDate> | |
| 48 | + <guid>http://twitter.com/codemirror/statuses/48527733722058752</guid> | |
| 49 | + <link>http://twitter.com/codemirror/statuses/48527733722058752</link> | |
| 50 | + <twitter:source>web</twitter:source> | |
| 51 | + <twitter:place/> | |
| 52 | + </item> | |
| 53 | + <item> | |
| 54 | + <title>codemirror: Posted a description of the CodeMirror 2 internals at | |
| 55 | + http://codemirror.net/2/internals.html</title> | |
| 56 | + <description>codemirror: Posted a description of the CodeMirror 2 internals at | |
| 57 | + http://codemirror.net/2/internals.html</description> | |
| 58 | + <pubDate>Wed, 02 Mar 2011 12:15:09 +0000</pubDate> | |
| 59 | + <guid>http://twitter.com/codemirror/statuses/42920879788789760</guid> | |
| 60 | + <link>http://twitter.com/codemirror/statuses/42920879788789760</link> | |
| 61 | + <twitter:source>web</twitter:source> | |
| 62 | + <twitter:place/> | |
| 63 | + </item> | |
| 64 | + </channel> | |
| 65 | +</rss></textarea></form> | |
| 66 | + | |
| 67 | + <script> | |
| 68 | +var editor = CodeMirror.fromTextArea(document.getElementById("code"), { | |
| 69 | + mode: "application/xml", | |
| 70 | + styleActiveLine: true, | |
| 71 | + lineNumbers: true, | |
| 72 | + lineWrapping: true | |
| 73 | +}); | |
| 74 | +</script> | |
| 75 | + | |
| 76 | + <p>Styling the current cursor line.</p> | |
| 77 | + | |
| 78 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,79 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Any Word Completion Demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<link rel="stylesheet" href="../addon/hint/show-hint.css"> | |
| 9 | +<script src="../lib/codemirror.js"></script> | |
| 10 | +<script src="../addon/hint/show-hint.js"></script> | |
| 11 | +<script src="../addon/hint/anyword-hint.js"></script> | |
| 12 | +<script src="../mode/javascript/javascript.js"></script> | |
| 13 | +<div id=nav> | |
| 14 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 15 | + | |
| 16 | + <ul> | |
| 17 | + <li><a href="../index.html">Home</a> | |
| 18 | + <li><a href="../doc/manual.html">Manual</a> | |
| 19 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 20 | + </ul> | |
| 21 | + <ul> | |
| 22 | + <li><a class=active href="#">Any Word Completion</a> | |
| 23 | + </ul> | |
| 24 | +</div> | |
| 25 | + | |
| 26 | +<article> | |
| 27 | +<h2>Any Word Completion Demo</h2> | |
| 28 | +<form><textarea id="code" name="code"> | |
| 29 | +(function() { | |
| 30 | + "use strict"; | |
| 31 | + | |
| 32 | + var WORD = /[\w$]+/g, RANGE = 500; | |
| 33 | + | |
| 34 | + CodeMirror.registerHelper("hint", "anyword", function(editor, options) { | |
| 35 | + var word = options && options.word || WORD; | |
| 36 | + var range = options && options.range || RANGE; | |
| 37 | + var cur = editor.getCursor(), curLine = editor.getLine(cur.line); | |
| 38 | + var start = cur.ch, end = start; | |
| 39 | + while (end < curLine.length && word.test(curLine.charAt(end))) ++end; | |
| 40 | + while (start && word.test(curLine.charAt(start - 1))) --start; | |
| 41 | + var curWord = start != end && curLine.slice(start, end); | |
| 42 | + | |
| 43 | + var list = [], seen = {}; | |
| 44 | + function scan(dir) { | |
| 45 | + var line = cur.line, end = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir; | |
| 46 | + for (; line != end; line += dir) { | |
| 47 | + var text = editor.getLine(line), m; | |
| 48 | + word.lastIndex = 0; | |
| 49 | + while (m = word.exec(text)) { | |
| 50 | + if ((!curWord || m[0].indexOf(curWord) == 0) && !seen.hasOwnProperty(m[0])) { | |
| 51 | + seen[m[0]] = true; | |
| 52 | + list.push(m[0]); | |
| 53 | + } | |
| 54 | + } | |
| 55 | + } | |
| 56 | + } | |
| 57 | + scan(-1); | |
| 58 | + scan(1); | |
| 59 | + return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)}; | |
| 60 | + }); | |
| 61 | +})(); | |
| 62 | +</textarea></form> | |
| 63 | + | |
| 64 | +<p>Press <strong>ctrl-space</strong> to activate autocompletion. The | |
| 65 | +completion uses | |
| 66 | +the <a href="../doc/manual.html#addon_anyword-hint">anyword-hint.js</a> | |
| 67 | +module, which simply looks at nearby words in the buffer and completes | |
| 68 | +to those.</p> | |
| 69 | + | |
| 70 | + <script> | |
| 71 | + CodeMirror.commands.autocomplete = function(cm) { | |
| 72 | + cm.showHint({hint: CodeMirror.hint.anyword}); | |
| 73 | + } | |
| 74 | + var editor = CodeMirror.fromTextArea(document.getElementById("code"), { | |
| 75 | + lineNumbers: true, | |
| 76 | + extraKeys: {"Ctrl-Space": "autocomplete"} | |
| 77 | + }); | |
| 78 | + </script> | |
| 79 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,74 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Bi-directional Text Demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<script src="../lib/codemirror.js"></script> | |
| 9 | +<script src="../mode/xml/xml.js"></script> | |
| 10 | +<style type="text/css"> | |
| 11 | + .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;} | |
| 12 | + </style> | |
| 13 | +<div id=nav> | |
| 14 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 15 | + | |
| 16 | + <ul> | |
| 17 | + <li><a href="../index.html">Home</a> | |
| 18 | + <li><a href="../doc/manual.html">Manual</a> | |
| 19 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 20 | + </ul> | |
| 21 | + <ul> | |
| 22 | + <li><a class=active href="#">Bi-directional Text</a> | |
| 23 | + </ul> | |
| 24 | +</div> | |
| 25 | + | |
| 26 | +<article> | |
| 27 | +<h2>Bi-directional Text Demo</h2> | |
| 28 | +<form><textarea id="code" name="code"><!-- Piece of the CodeMirror manual, 'translated' into Arabic by | |
| 29 | + Google Translate --> | |
| 30 | + | |
| 31 | +<dl> | |
| 32 | + <dt id=option_value><code>value (string or Doc)</code></dt> | |
| 33 | + <dd>قيمة البداية المحرر. يمكن أن تكون سلسلة، أو. كائن مستند.</dd> | |
| 34 | + <dt id=option_mode><code>mode (string or object)</code></dt> | |
| 35 | + <dd>وضع الاستخدام. عندما لا تعطى، وهذا الافتراضي إلى الطريقة الاولى | |
| 36 | + التي تم تحميلها. قد يكون من سلسلة، والتي إما أسماء أو ببساطة هو وضع | |
| 37 | + MIME نوع المرتبطة اسطة. بدلا من ذلك، قد يكون من كائن يحتوي على | |
| 38 | + خيارات التكوين لواسطة، مع <code>name</code> الخاصية التي وضع أسماء | |
| 39 | + (على سبيل المثال <code>{name: "javascript", json: true}</code>). | |
| 40 | + صفحات التجريبي لكل وضع تحتوي على معلومات حول ما معلمات تكوين وضع | |
| 41 | + يدعمها. يمكنك أن تطلب CodeMirror التي تم تعريفها طرق وأنواع MIME | |
| 42 | + الكشف على <code>CodeMirror.modes</code> | |
| 43 | + و <code>CodeMirror.mimeModes</code> الكائنات. وضع خرائط الأسماء | |
| 44 | + الأولى لمنشئات الخاصة بهم، وخرائط لأنواع MIME 2 المواصفات | |
| 45 | + واسطة.</dd> | |
| 46 | + <dt id=option_theme><code>theme (string)</code></dt> | |
| 47 | + <dd>موضوع لنمط المحرر مع. يجب عليك التأكد من الملف CSS تحديد | |
| 48 | + المقابلة <code>.cm-s-[name]</code> يتم تحميل أنماط (انظر | |
| 49 | + <a href="../theme/"><code>theme</code></a> الدليل في التوزيع). | |
| 50 | + الافتراضي هو <code>"default"</code> ، والتي تم تضمينها في | |
| 51 | + الألوان <code>codemirror.css</code>. فمن الممكن استخدام فئات متعددة | |
| 52 | + في تطبيق السمات مرة واحدة على سبيل المثال <code>"foo bar"</code> | |
| 53 | + سيتم تعيين كل من <code>cm-s-foo</code> و <code>cm-s-bar</code> | |
| 54 | + الطبقات إلى المحرر.</dd> | |
| 55 | +</dl> | |
| 56 | +</textarea></form> | |
| 57 | + | |
| 58 | + <script> | |
| 59 | +var editor = CodeMirror.fromTextArea(document.getElementById("code"), { | |
| 60 | + mode: "text/html", | |
| 61 | + lineNumbers: true | |
| 62 | +}); | |
| 63 | +</script> | |
| 64 | + | |
| 65 | + <p>Demonstration of bi-directional text support. See | |
| 66 | + the <a href="http://marijnhaverbeke.nl/blog/cursor-in-bidi-text.html">related | |
| 67 | + blog post</a> for more background.</p> | |
| 68 | + | |
| 69 | + <p><strong>Note:</strong> There is | |
| 70 | + a <a href="https://github.com/marijnh/CodeMirror/issues/1757">known | |
| 71 | + bug</a> with cursor motion and mouse clicks in bi-directional lines | |
| 72 | + that are line wrapped.</p> | |
| 73 | + | |
| 74 | +</article> | ... | ... |
| ... | ... | @@ -0,0 +1,85 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: B-Tree visualization</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<script src="../lib/codemirror.js"></script> | |
| 9 | +<style type="text/css"> | |
| 10 | + .lineblock { display: inline-block; margin: 1px; height: 5px; } | |
| 11 | + .CodeMirror {border: 1px solid #aaa; height: 400px} | |
| 12 | + </style> | |
| 13 | +<div id=nav> | |
| 14 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 15 | + | |
| 16 | + <ul> | |
| 17 | + <li><a href="../index.html">Home</a> | |
| 18 | + <li><a href="../doc/manual.html">Manual</a> | |
| 19 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 20 | + </ul> | |
| 21 | + <ul> | |
| 22 | + <li><a class=active href="#">B-Tree visualization</a> | |
| 23 | + </ul> | |
| 24 | +</div> | |
| 25 | + | |
| 26 | +<article> | |
| 27 | +<h2>B-Tree visualization</h2> | |
| 28 | +<form><textarea id="code" name="code">type here, see a summary of the document b-tree below</textarea></form> | |
| 29 | + </div> | |
| 30 | + <div style="display: inline-block; height: 402px; overflow-y: auto" id="output"></div> | |
| 31 | + </div> | |
| 32 | + | |
| 33 | + <script id="me"> | |
| 34 | +var editor = CodeMirror.fromTextArea(document.getElementById("code"), { | |
| 35 | + lineNumbers: true, | |
| 36 | + lineWrapping: true | |
| 37 | +}); | |
| 38 | +var updateTimeout; | |
| 39 | +editor.on("change", function(cm) { | |
| 40 | + clearTimeout(updateTimeout); | |
| 41 | + updateTimeout = setTimeout(updateVisual, 200); | |
| 42 | +}); | |
| 43 | +updateVisual(); | |
| 44 | + | |
| 45 | +function updateVisual() { | |
| 46 | + var out = document.getElementById("output"); | |
| 47 | + out.innerHTML = ""; | |
| 48 | + | |
| 49 | + function drawTree(out, node) { | |
| 50 | + if (node.lines) { | |
| 51 | + out.appendChild(document.createElement("div")).innerHTML = | |
| 52 | + "<b>leaf</b>: " + node.lines.length + " lines, " + Math.round(node.height) + " px"; | |
| 53 | + var lines = out.appendChild(document.createElement("div")); | |
| 54 | + lines.style.lineHeight = "6px"; lines.style.marginLeft = "10px"; | |
| 55 | + for (var i = 0; i < node.lines.length; ++i) { | |
| 56 | + var line = node.lines[i], lineElt = lines.appendChild(document.createElement("div")); | |
| 57 | + lineElt.className = "lineblock"; | |
| 58 | + var gray = Math.min(line.text.length * 3, 230), col = gray.toString(16); | |
| 59 | + if (col.length == 1) col = "0" + col; | |
| 60 | + lineElt.style.background = "#" + col + col + col; | |
| 61 | + lineElt.style.width = Math.max(Math.round(line.height / 3), 1) + "px"; | |
| 62 | + } | |
| 63 | + } else { | |
| 64 | + out.appendChild(document.createElement("div")).innerHTML = | |
| 65 | + "<b>node</b>: " + node.size + " lines, " + Math.round(node.height) + " px"; | |
| 66 | + var sub = out.appendChild(document.createElement("div")); | |
| 67 | + sub.style.paddingLeft = "20px"; | |
| 68 | + for (var i = 0; i < node.children.length; ++i) | |
| 69 | + drawTree(sub, node.children[i]); | |
| 70 | + } | |
| 71 | + } | |
| 72 | + drawTree(out, editor.getDoc()); | |
| 73 | +} | |
| 74 | + | |
| 75 | +function fillEditor() { | |
| 76 | + var sc = document.getElementById("me"); | |
| 77 | + var doc = (sc.textContent || sc.innerText || sc.innerHTML).replace(/^\s*/, "") + "\n"; | |
| 78 | + doc += doc; doc += doc; doc += doc; doc += doc; doc += doc; doc += doc; | |
| 79 | + editor.setValue(doc); | |
| 80 | +} | |
| 81 | + </script> | |
| 82 | + | |
| 83 | +<p><button onclick="fillEditor()">Add a lot of content</button></p> | |
| 84 | + | |
| 85 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,109 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Multiple Buffer & Split View Demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<script src="../lib/codemirror.js"></script> | |
| 9 | +<script src="../mode/javascript/javascript.js"></script> | |
| 10 | +<script src="../mode/css/css.js"></script> | |
| 11 | +<style type="text/css" id=style> | |
| 12 | + .CodeMirror {border: 1px solid black; height: 250px;} | |
| 13 | + </style> | |
| 14 | +<div id=nav> | |
| 15 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 16 | + | |
| 17 | + <ul> | |
| 18 | + <li><a href="../index.html">Home</a> | |
| 19 | + <li><a href="../doc/manual.html">Manual</a> | |
| 20 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 21 | + </ul> | |
| 22 | + <ul> | |
| 23 | + <li><a class=active href="#">Multiple Buffer & Split View</a> | |
| 24 | + </ul> | |
| 25 | +</div> | |
| 26 | + | |
| 27 | +<article> | |
| 28 | +<h2>Multiple Buffer & Split View Demo</h2> | |
| 29 | + | |
| 30 | + | |
| 31 | + <div id=code_top></div> | |
| 32 | + <div> | |
| 33 | + Select buffer: <select id=buffers_top></select> | |
| 34 | + <button onclick="newBuf('top')">New buffer</button> | |
| 35 | + </div> | |
| 36 | + <div id=code_bot></div> | |
| 37 | + <div> | |
| 38 | + Select buffer: <select id=buffers_bot></select> | |
| 39 | + <button onclick="newBuf('bot')">New buffer</button> | |
| 40 | + </div> | |
| 41 | + | |
| 42 | + <script id=script> | |
| 43 | +var sel_top = document.getElementById("buffers_top"); | |
| 44 | +CodeMirror.on(sel_top, "change", function() { | |
| 45 | + selectBuffer(ed_top, sel_top.options[sel_top.selectedIndex].value); | |
| 46 | +}); | |
| 47 | + | |
| 48 | +var sel_bot = document.getElementById("buffers_bot"); | |
| 49 | +CodeMirror.on(sel_bot, "change", function() { | |
| 50 | + selectBuffer(ed_bot, sel_bot.options[sel_bot.selectedIndex].value); | |
| 51 | +}); | |
| 52 | + | |
| 53 | +var buffers = {}; | |
| 54 | + | |
| 55 | +function openBuffer(name, text, mode) { | |
| 56 | + buffers[name] = CodeMirror.Doc(text, mode); | |
| 57 | + var opt = document.createElement("option"); | |
| 58 | + opt.appendChild(document.createTextNode(name)); | |
| 59 | + sel_top.appendChild(opt); | |
| 60 | + sel_bot.appendChild(opt.cloneNode(true)); | |
| 61 | +} | |
| 62 | + | |
| 63 | +function newBuf(where) { | |
| 64 | + var name = prompt("Name for the buffer", "*scratch*"); | |
| 65 | + if (name == null) return; | |
| 66 | + if (buffers.hasOwnProperty(name)) { | |
| 67 | + alert("There's already a buffer by that name."); | |
| 68 | + return; | |
| 69 | + } | |
| 70 | + openBuffer(name, "", "javascript"); | |
| 71 | + selectBuffer(where == "top" ? ed_top : ed_bot, name); | |
| 72 | + var sel = where == "top" ? sel_top : sel_bot; | |
| 73 | + sel.value = name; | |
| 74 | +} | |
| 75 | + | |
| 76 | +function selectBuffer(editor, name) { | |
| 77 | + var buf = buffers[name]; | |
| 78 | + if (buf.getEditor()) buf = buf.linkedDoc({sharedHist: true}); | |
| 79 | + var old = editor.swapDoc(buf); | |
| 80 | + var linked = old.iterLinkedDocs(function(doc) {linked = doc;}); | |
| 81 | + if (linked) { | |
| 82 | + // Make sure the document in buffers is the one the other view is looking at | |
| 83 | + for (var name in buffers) if (buffers[name] == old) buffers[name] = linked; | |
| 84 | + old.unlinkDoc(linked); | |
| 85 | + } | |
| 86 | + editor.focus(); | |
| 87 | +} | |
| 88 | + | |
| 89 | +function nodeContent(id) { | |
| 90 | + var node = document.getElementById(id), val = node.textContent || node.innerText; | |
| 91 | + val = val.slice(val.match(/^\s*/)[0].length, val.length - val.match(/\s*$/)[0].length) + "\n"; | |
| 92 | + return val; | |
| 93 | +} | |
| 94 | +openBuffer("js", nodeContent("script"), "javascript"); | |
| 95 | +openBuffer("css", nodeContent("style"), "css"); | |
| 96 | + | |
| 97 | +var ed_top = CodeMirror(document.getElementById("code_top"), {lineNumbers: true}); | |
| 98 | +selectBuffer(ed_top, "js"); | |
| 99 | +var ed_bot = CodeMirror(document.getElementById("code_bot"), {lineNumbers: true}); | |
| 100 | +selectBuffer(ed_bot, "js"); | |
| 101 | +</script> | |
| 102 | + | |
| 103 | + <p>Demonstration of | |
| 104 | + using <a href="../doc/manual.html#linkedDoc">linked documents</a> | |
| 105 | + to provide a split view on a document, and | |
| 106 | + using <a href="../doc/manual.html#swapDoc"><code>swapDoc</code></a> | |
| 107 | + to use a single editor to display multiple documents.</p> | |
| 108 | + | |
| 109 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,58 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Mode-Changing Demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<script src="../lib/codemirror.js"></script> | |
| 9 | +<script src="../mode/javascript/javascript.js"></script> | |
| 10 | +<script src="../mode/scheme/scheme.js"></script> | |
| 11 | +<style type="text/css"> | |
| 12 | + .CodeMirror {border: 1px solid black;} | |
| 13 | + </style> | |
| 14 | +<div id=nav> | |
| 15 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 16 | + | |
| 17 | + <ul> | |
| 18 | + <li><a href="../index.html">Home</a> | |
| 19 | + <li><a href="../doc/manual.html">Manual</a> | |
| 20 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 21 | + </ul> | |
| 22 | + <ul> | |
| 23 | + <li><a class=active href="#">Mode-Changing</a> | |
| 24 | + </ul> | |
| 25 | +</div> | |
| 26 | + | |
| 27 | +<article> | |
| 28 | +<h2>Mode-Changing Demo</h2> | |
| 29 | +<form><textarea id="code" name="code"> | |
| 30 | +;; If there is Scheme code in here, the editor will be in Scheme mode. | |
| 31 | +;; If you put in JS instead, it'll switch to JS mode. | |
| 32 | + | |
| 33 | +(define (double x) | |
| 34 | + (* x x)) | |
| 35 | +</textarea></form> | |
| 36 | + | |
| 37 | +<p>On changes to the content of the above editor, a (crude) script | |
| 38 | +tries to auto-detect the language used, and switches the editor to | |
| 39 | +either JavaScript or Scheme mode based on that.</p> | |
| 40 | + | |
| 41 | +<script> | |
| 42 | + var editor = CodeMirror.fromTextArea(document.getElementById("code"), { | |
| 43 | + mode: "scheme", | |
| 44 | + lineNumbers: true | |
| 45 | + }); | |
| 46 | + var pending; | |
| 47 | + editor.on("change", function() { | |
| 48 | + clearTimeout(pending); | |
| 49 | + pending = setTimeout(update, 400); | |
| 50 | + }); | |
| 51 | + function looksLikeScheme(code) { | |
| 52 | + return !/^\s*\(\s*function\b/.test(code) && /^\s*[;\(]/.test(code); | |
| 53 | + } | |
| 54 | + function update() { | |
| 55 | + editor.setOption("mode", looksLikeScheme(editor.getValue()) ? "scheme" : "javascript"); | |
| 56 | + } | |
| 57 | +</script> | |
| 58 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,52 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Closebrackets Demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<script src="../lib/codemirror.js"></script> | |
| 9 | +<script src="../addon/edit/closebrackets.js"></script> | |
| 10 | +<script src="../mode/javascript/javascript.js"></script> | |
| 11 | +<style type="text/css"> | |
| 12 | + .CodeMirror {border-top: 1px solid #888; border-bottom: 1px solid #888;} | |
| 13 | + </style> | |
| 14 | +<div id=nav> | |
| 15 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 16 | + | |
| 17 | + <ul> | |
| 18 | + <li><a href="../index.html">Home</a> | |
| 19 | + <li><a href="../doc/manual.html">Manual</a> | |
| 20 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 21 | + </ul> | |
| 22 | + <ul> | |
| 23 | + <li><a class=active href="#">Closebrackets</a> | |
| 24 | + </ul> | |
| 25 | +</div> | |
| 26 | + | |
| 27 | +<article> | |
| 28 | +<h2>Closebrackets Demo</h2> | |
| 29 | +<form><textarea id="code" name="code">function Grid(width, height) { | |
| 30 | + this.width = width; | |
| 31 | + this.height = height; | |
| 32 | + this.cells = new Array(width * height); | |
| 33 | +} | |
| 34 | +Grid.prototype.valueAt = function(point) { | |
| 35 | + return this.cells[point.y * this.width + point.x]; | |
| 36 | +}; | |
| 37 | +Grid.prototype.setValueAt = function(point, value) { | |
| 38 | + this.cells[point.y * this.width + point.x] = value; | |
| 39 | +}; | |
| 40 | +Grid.prototype.isInside = function(point) { | |
| 41 | + return point.x >= 0 && point.y >= 0 && | |
| 42 | + point.x < this.width && point.y < this.height; | |
| 43 | +}; | |
| 44 | +Grid.prototype.moveValue = function(from, to) { | |
| 45 | + this.setValueAt(to, this.valueAt(from)); | |
| 46 | + this.setValueAt(from, undefined); | |
| 47 | +};</textarea></form> | |
| 48 | + | |
| 49 | + <script type="text/javascript"> | |
| 50 | + var editor = CodeMirror.fromTextArea(document.getElementById("code"), {autoCloseBrackets: true}); | |
| 51 | + </script> | |
| 52 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,41 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Close-Tag Demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<script src="../lib/codemirror.js"></script> | |
| 9 | +<script src="../addon/edit/closetag.js"></script> | |
| 10 | +<script src="../addon/fold/xml-fold.js"></script> | |
| 11 | +<script src="../mode/xml/xml.js"></script> | |
| 12 | +<script src="../mode/javascript/javascript.js"></script> | |
| 13 | +<script src="../mode/css/css.js"></script> | |
| 14 | +<script src="../mode/htmlmixed/htmlmixed.js"></script> | |
| 15 | +<style type="text/css"> | |
| 16 | + .CodeMirror {border-top: 1px solid #888; border-bottom: 1px solid #888;} | |
| 17 | + </style> | |
| 18 | +<div id=nav> | |
| 19 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 20 | + | |
| 21 | + <ul> | |
| 22 | + <li><a href="../index.html">Home</a> | |
| 23 | + <li><a href="../doc/manual.html">Manual</a> | |
| 24 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 25 | + </ul> | |
| 26 | + <ul> | |
| 27 | + <li><a class=active href="#">Close-Tag</a> | |
| 28 | + </ul> | |
| 29 | +</div> | |
| 30 | + | |
| 31 | +<article> | |
| 32 | +<h2>Close-Tag Demo</h2> | |
| 33 | +<form><textarea id="code" name="code"><html</textarea></form> | |
| 34 | + | |
| 35 | + <script type="text/javascript"> | |
| 36 | + var editor = CodeMirror.fromTextArea(document.getElementById("code"), { | |
| 37 | + mode: 'text/html', | |
| 38 | + autoCloseTags: true | |
| 39 | + }); | |
| 40 | + </script> | |
| 41 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,79 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Autocomplete Demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<link rel="stylesheet" href="../addon/hint/show-hint.css"> | |
| 9 | +<script src="../lib/codemirror.js"></script> | |
| 10 | +<script src="../addon/hint/show-hint.js"></script> | |
| 11 | +<script src="../addon/hint/javascript-hint.js"></script> | |
| 12 | +<script src="../mode/javascript/javascript.js"></script> | |
| 13 | + | |
| 14 | +<div id=nav> | |
| 15 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 16 | + | |
| 17 | + <ul> | |
| 18 | + <li><a href="../index.html">Home</a> | |
| 19 | + <li><a href="../doc/manual.html">Manual</a> | |
| 20 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 21 | + </ul> | |
| 22 | + <ul> | |
| 23 | + <li><a class=active href="#">Autocomplete</a> | |
| 24 | + </ul> | |
| 25 | +</div> | |
| 26 | + | |
| 27 | +<article> | |
| 28 | +<h2>Autocomplete Demo</h2> | |
| 29 | +<form><textarea id="code" name="code"> | |
| 30 | +function getCompletions(token, context) { | |
| 31 | + var found = [], start = token.string; | |
| 32 | + function maybeAdd(str) { | |
| 33 | + if (str.indexOf(start) == 0) found.push(str); | |
| 34 | + } | |
| 35 | + function gatherCompletions(obj) { | |
| 36 | + if (typeof obj == "string") forEach(stringProps, maybeAdd); | |
| 37 | + else if (obj instanceof Array) forEach(arrayProps, maybeAdd); | |
| 38 | + else if (obj instanceof Function) forEach(funcProps, maybeAdd); | |
| 39 | + for (var name in obj) maybeAdd(name); | |
| 40 | + } | |
| 41 | + | |
| 42 | + if (context) { | |
| 43 | + // If this is a property, see if it belongs to some object we can | |
| 44 | + // find in the current environment. | |
| 45 | + var obj = context.pop(), base; | |
| 46 | + if (obj.className == "js-variable") | |
| 47 | + base = window[obj.string]; | |
| 48 | + else if (obj.className == "js-string") | |
| 49 | + base = ""; | |
| 50 | + else if (obj.className == "js-atom") | |
| 51 | + base = 1; | |
| 52 | + while (base != null && context.length) | |
| 53 | + base = base[context.pop().string]; | |
| 54 | + if (base != null) gatherCompletions(base); | |
| 55 | + } | |
| 56 | + else { | |
| 57 | + // If not, just look in the window object and any local scope | |
| 58 | + // (reading into JS mode internals to get at the local variables) | |
| 59 | + for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name); | |
| 60 | + gatherCompletions(window); | |
| 61 | + forEach(keywords, maybeAdd); | |
| 62 | + } | |
| 63 | + return found; | |
| 64 | +} | |
| 65 | +</textarea></form> | |
| 66 | + | |
| 67 | +<p>Press <strong>ctrl-space</strong> to activate autocompletion. Built | |
| 68 | +on top of the <a href="../doc/manual.html#addon_show-hint"><code>show-hint</code></a> | |
| 69 | +and <a href="../doc/manual.html#addon_javascript-hint"><code>javascript-hint</code></a> | |
| 70 | +addons.</p> | |
| 71 | + | |
| 72 | + <script> | |
| 73 | + var editor = CodeMirror.fromTextArea(document.getElementById("code"), { | |
| 74 | + lineNumbers: true, | |
| 75 | + extraKeys: {"Ctrl-Space": "autocomplete"}, | |
| 76 | + mode: {name: "javascript", globalVars: true} | |
| 77 | + }); | |
| 78 | + </script> | |
| 79 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,75 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Emacs bindings demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<link rel="stylesheet" href="../addon/dialog/dialog.css"> | |
| 9 | +<script src="../lib/codemirror.js"></script> | |
| 10 | +<script src="../mode/clike/clike.js"></script> | |
| 11 | +<script src="../keymap/emacs.js"></script> | |
| 12 | +<script src="../addon/edit/matchbrackets.js"></script> | |
| 13 | +<script src="../addon/comment/comment.js"></script> | |
| 14 | +<script src="../addon/dialog/dialog.js"></script> | |
| 15 | +<script src="../addon/search/searchcursor.js"></script> | |
| 16 | +<script src="../addon/search/search.js"></script> | |
| 17 | +<style type="text/css"> | |
| 18 | + .CodeMirror {border-top: 1px solid #eee; border-bottom: 1px solid #eee;} | |
| 19 | + </style> | |
| 20 | +<div id=nav> | |
| 21 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 22 | + | |
| 23 | + <ul> | |
| 24 | + <li><a href="../index.html">Home</a> | |
| 25 | + <li><a href="../doc/manual.html">Manual</a> | |
| 26 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 27 | + </ul> | |
| 28 | + <ul> | |
| 29 | + <li><a class=active href="#">Emacs bindings</a> | |
| 30 | + </ul> | |
| 31 | +</div> | |
| 32 | + | |
| 33 | +<article> | |
| 34 | +<h2>Emacs bindings demo</h2> | |
| 35 | +<form><textarea id="code" name="code"> | |
| 36 | +#include "syscalls.h" | |
| 37 | +/* getchar: simple buffered version */ | |
| 38 | +int getchar(void) | |
| 39 | +{ | |
| 40 | + static char buf[BUFSIZ]; | |
| 41 | + static char *bufp = buf; | |
| 42 | + static int n = 0; | |
| 43 | + if (n == 0) { /* buffer is empty */ | |
| 44 | + n = read(0, buf, sizeof buf); | |
| 45 | + bufp = buf; | |
| 46 | + } | |
| 47 | + return (--n >= 0) ? (unsigned char) *bufp++ : EOF; | |
| 48 | +} | |
| 49 | +</textarea></form> | |
| 50 | + | |
| 51 | +<p>The emacs keybindings are enabled by | |
| 52 | +including <a href="../keymap/emacs.js">keymap/emacs.js</a> and setting | |
| 53 | +the <code>keyMap</code> option to <code>"emacs"</code>. Because | |
| 54 | +CodeMirror's internal API is quite different from Emacs, they are only | |
| 55 | +a loose approximation of actual emacs bindings, though.</p> | |
| 56 | + | |
| 57 | +<p>Also note that a lot of browsers disallow certain keys from being | |
| 58 | +captured. For example, Chrome blocks both Ctrl-W and Ctrl-N, with the | |
| 59 | +result that idiomatic use of Emacs keys will constantly close your tab | |
| 60 | +or open a new window.</p> | |
| 61 | + | |
| 62 | + <script> | |
| 63 | + CodeMirror.commands.save = function() { | |
| 64 | + var elt = editor.getWrapperElement(); | |
| 65 | + elt.style.background = "#def"; | |
| 66 | + setTimeout(function() { elt.style.background = ""; }, 300); | |
| 67 | + }; | |
| 68 | + var editor = CodeMirror.fromTextArea(document.getElementById("code"), { | |
| 69 | + lineNumbers: true, | |
| 70 | + mode: "text/x-csrc", | |
| 71 | + keyMap: "emacs" | |
| 72 | + }); | |
| 73 | + </script> | |
| 74 | + | |
| 75 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,95 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<head> | |
| 4 | + <title>CodeMirror: Code Folding Demo</title> | |
| 5 | + <meta charset="utf-8"/> | |
| 6 | + <link rel=stylesheet href="../doc/docs.css"> | |
| 7 | + | |
| 8 | + <link rel="stylesheet" href="../lib/codemirror.css"> | |
| 9 | + <link rel="stylesheet" href="../addon/fold/foldgutter.css" /> | |
| 10 | + <script src="../lib/codemirror.js"></script> | |
| 11 | + <script src="../addon/fold/foldcode.js"></script> | |
| 12 | + <script src="../addon/fold/foldgutter.js"></script> | |
| 13 | + <script src="../addon/fold/brace-fold.js"></script> | |
| 14 | + <script src="../addon/fold/xml-fold.js"></script> | |
| 15 | + <script src="../addon/fold/markdown-fold.js"></script> | |
| 16 | + <script src="../addon/fold/comment-fold.js"></script> | |
| 17 | + <script src="../mode/javascript/javascript.js"></script> | |
| 18 | + <script src="../mode/xml/xml.js"></script> | |
| 19 | + <script src="../mode/markdown/markdown.js"></script> | |
| 20 | + <style type="text/css"> | |
| 21 | + .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;} | |
| 22 | + </style> | |
| 23 | +</head> | |
| 24 | + | |
| 25 | +<body> | |
| 26 | +<div id=nav> | |
| 27 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 28 | + | |
| 29 | + <ul> | |
| 30 | + <li><a href="../index.html">Home</a> | |
| 31 | + <li><a href="../doc/manual.html">Manual</a> | |
| 32 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 33 | + </ul> | |
| 34 | + <ul> | |
| 35 | + <li><a class=active href="#">Code Folding</a> | |
| 36 | + </ul> | |
| 37 | +</div> | |
| 38 | + | |
| 39 | +<article> | |
| 40 | + <h2>Code Folding Demo</h2> | |
| 41 | + <form> | |
| 42 | + <div style="max-width: 50em; margin-bottom: 1em">JavaScript:<br> | |
| 43 | + <textarea id="code" name="code"></textarea></div> | |
| 44 | + <div style="max-width: 50em; margin-bottom: 1em">HTML:<br> | |
| 45 | + <textarea id="code-html" name="code-html"></textarea></div> | |
| 46 | + <div style="max-width: 50em">Markdown:<br> | |
| 47 | + <textarea id="code-markdown" name="code"></textarea></div> | |
| 48 | + </form> | |
| 49 | + <script id="script"> | |
| 50 | +/* | |
| 51 | + * Demonstration of code folding | |
| 52 | + */ | |
| 53 | +window.onload = function() { | |
| 54 | + var te = document.getElementById("code"); | |
| 55 | + var sc = document.getElementById("script"); | |
| 56 | + te.value = (sc.textContent || sc.innerText || sc.innerHTML).replace(/^\s*/, ""); | |
| 57 | + sc.innerHTML = ""; | |
| 58 | + var te_html = document.getElementById("code-html"); | |
| 59 | + te_html.value = document.documentElement.innerHTML; | |
| 60 | + var te_markdown = document.getElementById("code-markdown"); | |
| 61 | + te_markdown.value = "# Foo\n## Bar\n\nblah blah\n\n## Baz\n\nblah blah\n\n# Quux\n\nblah blah\n" | |
| 62 | + | |
| 63 | + window.editor = CodeMirror.fromTextArea(te, { | |
| 64 | + mode: "javascript", | |
| 65 | + lineNumbers: true, | |
| 66 | + lineWrapping: true, | |
| 67 | + extraKeys: {"Ctrl-Q": function(cm){ cm.foldCode(cm.getCursor()); }}, | |
| 68 | + foldGutter: true, | |
| 69 | + gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"] | |
| 70 | + }); | |
| 71 | + editor.foldCode(CodeMirror.Pos(13, 0)); | |
| 72 | + | |
| 73 | + window.editor_html = CodeMirror.fromTextArea(te_html, { | |
| 74 | + mode: "text/html", | |
| 75 | + lineNumbers: true, | |
| 76 | + lineWrapping: true, | |
| 77 | + extraKeys: {"Ctrl-Q": function(cm){ cm.foldCode(cm.getCursor()); }}, | |
| 78 | + foldGutter: true, | |
| 79 | + gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"] | |
| 80 | + }); | |
| 81 | + editor_html.foldCode(CodeMirror.Pos(0, 0)); | |
| 82 | + editor_html.foldCode(CodeMirror.Pos(21, 0)); | |
| 83 | + | |
| 84 | + window.editor_markdown = CodeMirror.fromTextArea(te_markdown, { | |
| 85 | + mode: "markdown", | |
| 86 | + lineNumbers: true, | |
| 87 | + lineWrapping: true, | |
| 88 | + extraKeys: {"Ctrl-Q": function(cm){ cm.foldCode(cm.getCursor()); }}, | |
| 89 | + foldGutter: true, | |
| 90 | + gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"] | |
| 91 | + }); | |
| 92 | +}; | |
| 93 | + </script> | |
| 94 | +</article> | |
| 95 | +</body> | ... | ... |
| ... | ... | @@ -0,0 +1,83 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Full Screen Editing</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<link rel="stylesheet" href="../addon/display/fullscreen.css"> | |
| 9 | +<link rel="stylesheet" href="../theme/night.css"> | |
| 10 | +<script src="../lib/codemirror.js"></script> | |
| 11 | +<script src="../mode/xml/xml.js"></script> | |
| 12 | +<script src="../addon/display/fullscreen.js"></script> | |
| 13 | + | |
| 14 | +<div id=nav> | |
| 15 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 16 | + | |
| 17 | + <ul> | |
| 18 | + <li><a href="../index.html">Home</a> | |
| 19 | + <li><a href="../doc/manual.html">Manual</a> | |
| 20 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 21 | + </ul> | |
| 22 | + <ul> | |
| 23 | + <li><a class=active href="#">Full Screen Editing</a> | |
| 24 | + </ul> | |
| 25 | +</div> | |
| 26 | + | |
| 27 | +<article> | |
| 28 | +<h2>Full Screen Editing</h2> | |
| 29 | +<form><textarea id="code" name="code" rows="5"> | |
| 30 | +<dl> | |
| 31 | + <dt id="option_indentWithTabs"><code><strong>indentWithTabs</strong>: boolean</code></dt> | |
| 32 | + <dd>Whether, when indenting, the first N*<code>tabSize</code> | |
| 33 | + spaces should be replaced by N tabs. Default is false.</dd> | |
| 34 | + | |
| 35 | + <dt id="option_electricChars"><code><strong>electricChars</strong>: boolean</code></dt> | |
| 36 | + <dd>Configures whether the editor should re-indent the current | |
| 37 | + line when a character is typed that might change its proper | |
| 38 | + indentation (only works if the mode supports indentation). | |
| 39 | + Default is true.</dd> | |
| 40 | + | |
| 41 | + <dt id="option_specialChars"><code><strong>specialChars</strong>: RegExp</code></dt> | |
| 42 | + <dd>A regular expression used to determine which characters | |
| 43 | + should be replaced by a | |
| 44 | + special <a href="#option_specialCharPlaceholder">placeholder</a>. | |
| 45 | + Mostly useful for non-printing special characters. The default | |
| 46 | + is <code>/[\u0000-\u0019\u00ad\u200b\u2028\u2029\ufeff]/</code>.</dd> | |
| 47 | + <dt id="option_specialCharPlaceholder"><code><strong>specialCharPlaceholder</strong>: function(char) → Element</code></dt> | |
| 48 | + <dd>A function that, given a special character identified by | |
| 49 | + the <a href="#option_specialChars"><code>specialChars</code></a> | |
| 50 | + option, produces a DOM node that is used to represent the | |
| 51 | + character. By default, a red dot (<span style="color: red">•</span>) | |
| 52 | + is shown, with a title tooltip to indicate the character code.</dd> | |
| 53 | + | |
| 54 | + <dt id="option_rtlMoveVisually"><code><strong>rtlMoveVisually</strong>: boolean</code></dt> | |
| 55 | + <dd>Determines whether horizontal cursor movement through | |
| 56 | + right-to-left (Arabic, Hebrew) text is visual (pressing the left | |
| 57 | + arrow moves the cursor left) or logical (pressing the left arrow | |
| 58 | + moves to the next lower index in the string, which is visually | |
| 59 | + right in right-to-left text). The default is <code>false</code> | |
| 60 | + on Windows, and <code>true</code> on other platforms.</dd> | |
| 61 | +</dl> | |
| 62 | +</textarea></form> | |
| 63 | + <script> | |
| 64 | + var editor = CodeMirror.fromTextArea(document.getElementById("code"), { | |
| 65 | + lineNumbers: true, | |
| 66 | + theme: "night", | |
| 67 | + extraKeys: { | |
| 68 | + "F11": function(cm) { | |
| 69 | + cm.setOption("fullScreen", !cm.getOption("fullScreen")); | |
| 70 | + }, | |
| 71 | + "Esc": function(cm) { | |
| 72 | + if (cm.getOption("fullScreen")) cm.setOption("fullScreen", false); | |
| 73 | + } | |
| 74 | + } | |
| 75 | + }); | |
| 76 | + </script> | |
| 77 | + | |
| 78 | + <p>Demonstration of | |
| 79 | + the <a href="../doc/manual.html#addon_fullscreen">fullscreen</a> | |
| 80 | + addon. Press <strong>F11</strong> when cursor is in the editor to | |
| 81 | + toggle full screen editing. <strong>Esc</strong> can also be used | |
| 82 | + to <i>exit</i> full screen editing.</p> | |
| 83 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,72 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Hard-wrapping Demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<script src="../lib/codemirror.js"></script> | |
| 9 | +<script src="../mode/markdown/markdown.js"></script> | |
| 10 | +<script src="../addon/wrap/hardwrap.js"></script> | |
| 11 | +<style type="text/css"> | |
| 12 | + .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;} | |
| 13 | +</style> | |
| 14 | +<div id=nav> | |
| 15 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 16 | + | |
| 17 | + <ul> | |
| 18 | + <li><a href="../index.html">Home</a> | |
| 19 | + <li><a href="../doc/manual.html">Manual</a> | |
| 20 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 21 | + </ul> | |
| 22 | + <ul> | |
| 23 | + <li><a class=active href="#">Hard-wrapping</a> | |
| 24 | + </ul> | |
| 25 | +</div> | |
| 26 | + | |
| 27 | +<article> | |
| 28 | +<h2>Hard-wrapping Demo</h2> | |
| 29 | +<form><textarea id="code" name="code">Lorem ipsum dolor sit amet, vim augue dictas constituto ex, | |
| 30 | +sit falli simul viderer te. Graeco scaevola maluisset sit | |
| 31 | +ut, in idque viris praesent sea. Ea sea eirmod indoctum | |
| 32 | +repudiare. Vel noluisse suscipit pericula ut. In ius nulla | |
| 33 | +alienum molestie. Mei essent discere democritum id. | |
| 34 | + | |
| 35 | +Equidem ponderum expetendis ius in, mea an erroribus | |
| 36 | +constituto, congue timeam perfecto ad est. Ius ut primis | |
| 37 | +timeam, per in ullum mediocrem. An case vero labitur pri, | |
| 38 | +vel dicit laoreet et. An qui prompta conclusionemque, eam | |
| 39 | +timeam sapientem in, cum dictas epicurei eu. | |
| 40 | + | |
| 41 | +Usu cu vide dictas deseruisse, eum choro graece adipiscing | |
| 42 | +ut. Cibo qualisque ius ad, et dicat scripta mea, eam nihil | |
| 43 | +mentitum aliquando cu. Debet aperiam splendide at quo, ad | |
| 44 | +paulo nostro commodo duo. Sea adhuc utinam conclusionemque | |
| 45 | +id, quas doming malorum nec ad. Tollit eruditi vivendum ad | |
| 46 | +ius, eos soleat ignota ad. | |
| 47 | +</textarea></form> | |
| 48 | + | |
| 49 | +<p>Demonstration of | |
| 50 | +the <a href="../doc/manual.html#addon_hardwrap">hardwrap</a> addon. | |
| 51 | +The above editor has its change event hooked up to | |
| 52 | +the <code>wrapParagraphsInRange</code> method, so that the paragraphs | |
| 53 | +are reflown as you are typing.</p> | |
| 54 | + | |
| 55 | +<script> | |
| 56 | +var editor = CodeMirror.fromTextArea(document.getElementById("code"), { | |
| 57 | + mode: "markdown", | |
| 58 | + lineNumbers: true, | |
| 59 | + extraKeys: { | |
| 60 | + "Ctrl-Q": function(cm) { cm.wrapParagraph(cm.getCursor(), options); } | |
| 61 | + } | |
| 62 | +}); | |
| 63 | +var wait, options = {column: 60}; | |
| 64 | +editor.on("change", function(cm, change) { | |
| 65 | + clearTimeout(wait); | |
| 66 | + wait = setTimeout(function() { | |
| 67 | + console.log(cm.wrapParagraphsInRange(change.from, CodeMirror.changeEnd(change), options)); | |
| 68 | + }, 200); | |
| 69 | +}); | |
| 70 | +</script> | |
| 71 | + | |
| 72 | +</article> | ... | ... |
| ... | ... | @@ -0,0 +1,56 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<head> | |
| 4 | + <title>CodeMirror: HTML completion demo</title> | |
| 5 | + <meta charset="utf-8"/> | |
| 6 | + <link rel=stylesheet href="../doc/docs.css"> | |
| 7 | + | |
| 8 | + <link rel="stylesheet" href="../lib/codemirror.css"> | |
| 9 | + <link rel="stylesheet" href="../addon/hint/show-hint.css"> | |
| 10 | + <script src="../lib/codemirror.js"></script> | |
| 11 | + <script src="../addon/hint/show-hint.js"></script> | |
| 12 | + <script src="../addon/hint/xml-hint.js"></script> | |
| 13 | + <script src="../addon/hint/html-hint.js"></script> | |
| 14 | + <script src="../mode/xml/xml.js"></script> | |
| 15 | + <script src="../mode/javascript/javascript.js"></script> | |
| 16 | + <script src="../mode/css/css.js"></script> | |
| 17 | + <script src="../mode/htmlmixed/htmlmixed.js"></script> | |
| 18 | + <style type="text/css"> | |
| 19 | + .CodeMirror {border-top: 1px solid #888; border-bottom: 1px solid #888;} | |
| 20 | + </style> | |
| 21 | +</head> | |
| 22 | + | |
| 23 | +<body> | |
| 24 | + <div id=nav> | |
| 25 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 26 | + | |
| 27 | + <ul> | |
| 28 | + <li><a href="../index.html">Home</a> | |
| 29 | + <li><a href="../doc/manual.html">Manual</a> | |
| 30 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 31 | + </ul> | |
| 32 | + <ul> | |
| 33 | + <li><a class=active href="#">HTML completion</a> | |
| 34 | + </ul> | |
| 35 | + </div> | |
| 36 | + | |
| 37 | + <article> | |
| 38 | + <h2>HTML completion demo</h2> | |
| 39 | + | |
| 40 | + <p>Shows the <a href="xmlcomplete.html">XML completer</a> | |
| 41 | + parameterized with information about the tags in HTML. | |
| 42 | + Press <strong>ctrl-space</strong> to activate completion.</p> | |
| 43 | + | |
| 44 | + <div id="code"></div> | |
| 45 | + | |
| 46 | + <script type="text/javascript"> | |
| 47 | + window.onload = function() { | |
| 48 | + editor = CodeMirror(document.getElementById("code"), { | |
| 49 | + mode: "text/html", | |
| 50 | + extraKeys: {"Ctrl-Space": "autocomplete"}, | |
| 51 | + value: document.documentElement.innerHTML | |
| 52 | + }); | |
| 53 | + }; | |
| 54 | + </script> | |
| 55 | + </article> | |
| 56 | +</body> | ... | ... |
| ... | ... | @@ -0,0 +1,59 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Indented wrapped line demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<script src="../lib/codemirror.js"></script> | |
| 9 | +<script src="../mode/xml/xml.js"></script> | |
| 10 | +<style type="text/css"> | |
| 11 | + .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;} | |
| 12 | + .CodeMirror pre > * { text-indent: 0px; } | |
| 13 | + </style> | |
| 14 | +<div id=nav> | |
| 15 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 16 | + | |
| 17 | + <ul> | |
| 18 | + <li><a href="../index.html">Home</a> | |
| 19 | + <li><a href="../doc/manual.html">Manual</a> | |
| 20 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 21 | + </ul> | |
| 22 | + <ul> | |
| 23 | + <li><a class=active href="#">Indented wrapped line</a> | |
| 24 | + </ul> | |
| 25 | +</div> | |
| 26 | + | |
| 27 | +<article> | |
| 28 | +<h2>Indented wrapped line demo</h2> | |
| 29 | +<form><textarea id="code" name="code"> | |
| 30 | +<!doctype html> | |
| 31 | +<body> | |
| 32 | + <h2 id="overview">Overview</h2> | |
| 33 | + | |
| 34 | + <p>CodeMirror is a code-editor component that can be embedded in Web pages. The core library provides <em>only</em> 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 <a href="#addons">add-ons</a> included in the distribution, and the <a href="https://github.com/jagthedrummer/codemirror-ui">CodeMirror UI</a> project, for reusable implementations of extra features.</p> | |
| 35 | + | |
| 36 | + <p>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 <a href="../mode/"><code>mode/</code></a> directory), and it isn't hard to <a href="#modeapi">write new ones</a> for other languages.</p> | |
| 37 | +</body> | |
| 38 | +</textarea></form> | |
| 39 | + | |
| 40 | + <p>This page uses a hack on top of the <code>"renderLine"</code> | |
| 41 | + event to make wrapped text line up with the base indentation of | |
| 42 | + the line.</p> | |
| 43 | + | |
| 44 | + <script> | |
| 45 | + var editor = CodeMirror.fromTextArea(document.getElementById("code"), { | |
| 46 | + lineNumbers: true, | |
| 47 | + lineWrapping: true, | |
| 48 | + mode: "text/html" | |
| 49 | + }); | |
| 50 | + var charWidth = editor.defaultCharWidth(), basePadding = 4; | |
| 51 | + editor.on("renderLine", function(cm, line, elt) { | |
| 52 | + var off = CodeMirror.countColumn(line.text, null, cm.getOption("tabSize")) * charWidth; | |
| 53 | + elt.style.textIndent = "-" + off + "px"; | |
| 54 | + elt.style.paddingLeft = (basePadding + off) + "px"; | |
| 55 | + }); | |
| 56 | + editor.refresh(); | |
| 57 | + </script> | |
| 58 | + | |
| 59 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,171 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Linter Demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<link rel="stylesheet" href="../addon/lint/lint.css"> | |
| 9 | +<script src="../lib/codemirror.js"></script> | |
| 10 | +<script src="../mode/javascript/javascript.js"></script> | |
| 11 | +<script src="../mode/css/css.js"></script> | |
| 12 | +<script src="//ajax.aspnetcdn.com/ajax/jshint/r07/jshint.js"></script> | |
| 13 | +<script src="https://rawgithub.com/zaach/jsonlint/79b553fb65c192add9066da64043458981b3972b/lib/jsonlint.js"></script> | |
| 14 | +<script src="https://rawgithub.com/stubbornella/csslint/master/release/csslint.js"></script> | |
| 15 | +<script src="../addon/lint/lint.js"></script> | |
| 16 | +<script src="../addon/lint/javascript-lint.js"></script> | |
| 17 | +<script src="../addon/lint/json-lint.js"></script> | |
| 18 | +<script src="../addon/lint/css-lint.js"></script> | |
| 19 | +<style type="text/css"> | |
| 20 | + .CodeMirror {border: 1px solid black;} | |
| 21 | + </style> | |
| 22 | +<div id=nav> | |
| 23 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 24 | + | |
| 25 | + <ul> | |
| 26 | + <li><a href="../index.html">Home</a> | |
| 27 | + <li><a href="../doc/manual.html">Manual</a> | |
| 28 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 29 | + </ul> | |
| 30 | + <ul> | |
| 31 | + <li><a class=active href="#">Linter</a> | |
| 32 | + </ul> | |
| 33 | +</div> | |
| 34 | + | |
| 35 | +<article> | |
| 36 | +<h2>Linter Demo</h2> | |
| 37 | + | |
| 38 | + | |
| 39 | + <p><textarea id="code-js">var widgets = [] | |
| 40 | +function updateHints() { | |
| 41 | + editor.operation(function(){ | |
| 42 | + for (var i = 0; i < widgets.length; ++i) | |
| 43 | + editor.removeLineWidget(widgets[i]); | |
| 44 | + widgets.length = 0; | |
| 45 | + | |
| 46 | + JSHINT(editor.getValue()); | |
| 47 | + for (var i = 0; i < JSHINT.errors.length; ++i) { | |
| 48 | + var err = JSHINT.errors[i]; | |
| 49 | + if (!err) continue; | |
| 50 | + var msg = document.createElement("div"); | |
| 51 | + var icon = msg.appendChild(document.createElement("span")); | |
| 52 | + icon.innerHTML = "!!"; | |
| 53 | + icon.className = "lint-error-icon"; | |
| 54 | + msg.appendChild(document.createTextNode(err.reason)); | |
| 55 | + msg.className = "lint-error"; | |
| 56 | + widgets.push(editor.addLineWidget(err.line - 1, msg, {coverGutter: false, noHScroll: true})); | |
| 57 | + } | |
| 58 | + }); | |
| 59 | + var info = editor.getScrollInfo(); | |
| 60 | + var after = editor.charCoords({line: editor.getCursor().line + 1, ch: 0}, "local").top; | |
| 61 | + if (info.top + info.clientHeight < after) | |
| 62 | + editor.scrollTo(null, after - info.clientHeight + 3); | |
| 63 | +} | |
| 64 | +</textarea></p> | |
| 65 | + | |
| 66 | + <p><textarea id="code-json">[ | |
| 67 | + { | |
| 68 | + _id: "post 1", | |
| 69 | + "author": "Bob", | |
| 70 | + "content": "...", | |
| 71 | + "page_views": 5 | |
| 72 | + }, | |
| 73 | + { | |
| 74 | + "_id": "post 2", | |
| 75 | + "author": "Bob", | |
| 76 | + "content": "...", | |
| 77 | + "page_views": 9 | |
| 78 | + }, | |
| 79 | + { | |
| 80 | + "_id": "post 3", | |
| 81 | + "author": "Bob", | |
| 82 | + "content": "...", | |
| 83 | + "page_views": 8 | |
| 84 | + } | |
| 85 | +] | |
| 86 | +</textarea></p> | |
| 87 | + | |
| 88 | + <p><textarea id="code-css">@charset "UTF-8"; | |
| 89 | + | |
| 90 | +@import url("booya.css") print, screen; | |
| 91 | +@import "whatup.css" screen; | |
| 92 | +@import "wicked.css"; | |
| 93 | + | |
| 94 | +/*Error*/ | |
| 95 | +@charset "UTF-8"; | |
| 96 | + | |
| 97 | + | |
| 98 | +@namespace "http://www.w3.org/1999/xhtml"; | |
| 99 | +@namespace svg "http://www.w3.org/2000/svg"; | |
| 100 | + | |
| 101 | +/*Warning: empty ruleset */ | |
| 102 | +.foo { | |
| 103 | +} | |
| 104 | + | |
| 105 | +h1 { | |
| 106 | + font-weight: bold; | |
| 107 | +} | |
| 108 | + | |
| 109 | +/*Warning: qualified heading */ | |
| 110 | +.foo h1 { | |
| 111 | + font-weight: bold; | |
| 112 | +} | |
| 113 | + | |
| 114 | +/*Warning: adjoining classes */ | |
| 115 | +.foo.bar { | |
| 116 | + zoom: 1; | |
| 117 | +} | |
| 118 | + | |
| 119 | +li.inline { | |
| 120 | + width: 100%; /*Warning: 100% can be problematic*/ | |
| 121 | +} | |
| 122 | + | |
| 123 | +li.last { | |
| 124 | + display: inline; | |
| 125 | + padding-left: 3px !important; | |
| 126 | + padding-right: 3px; | |
| 127 | + border-right: 0px; | |
| 128 | +} | |
| 129 | + | |
| 130 | +@media print { | |
| 131 | + li.inline { | |
| 132 | + color: black; | |
| 133 | + } | |
| 134 | +} | |
| 135 | + | |
| 136 | +@page { | |
| 137 | + margin: 10%; | |
| 138 | + counter-increment: page; | |
| 139 | + | |
| 140 | + @top-center { | |
| 141 | + font-family: sans-serif; | |
| 142 | + font-weight: bold; | |
| 143 | + font-size: 2em; | |
| 144 | + content: counter(page); | |
| 145 | + } | |
| 146 | +} | |
| 147 | +</textarea></p> | |
| 148 | +<script> | |
| 149 | + var editor = CodeMirror.fromTextArea(document.getElementById("code-js"), { | |
| 150 | + lineNumbers: true, | |
| 151 | + mode: "javascript", | |
| 152 | + gutters: ["CodeMirror-lint-markers"], | |
| 153 | + lint: true | |
| 154 | + }); | |
| 155 | + | |
| 156 | + var editor_json = CodeMirror.fromTextArea(document.getElementById("code-json"), { | |
| 157 | + lineNumbers: true, | |
| 158 | + mode: "application/json", | |
| 159 | + gutters: ["CodeMirror-lint-markers"], | |
| 160 | + lint: true | |
| 161 | + }); | |
| 162 | + | |
| 163 | + var editor_css = CodeMirror.fromTextArea(document.getElementById("code-css"), { | |
| 164 | + lineNumbers: true, | |
| 165 | + mode: "css", | |
| 166 | + gutters: ["CodeMirror-lint-markers"], | |
| 167 | + lint: true | |
| 168 | + }); | |
| 169 | +</script> | |
| 170 | + | |
| 171 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,49 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Lazy Mode Loading Demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<script src="../lib/codemirror.js"></script> | |
| 9 | +<script src="../addon/mode/loadmode.js"></script> | |
| 10 | +<style type="text/css"> | |
| 11 | + .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;} | |
| 12 | + </style> | |
| 13 | +<div id=nav> | |
| 14 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 15 | + | |
| 16 | + <ul> | |
| 17 | + <li><a href="../index.html">Home</a> | |
| 18 | + <li><a href="../doc/manual.html">Manual</a> | |
| 19 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 20 | + </ul> | |
| 21 | + <ul> | |
| 22 | + <li><a class=active href="#">Lazy Mode Loading</a> | |
| 23 | + </ul> | |
| 24 | +</div> | |
| 25 | + | |
| 26 | +<article> | |
| 27 | +<h2>Lazy Mode Loading Demo</h2> | |
| 28 | +<form><textarea id="code" name="code">This is the editor. | |
| 29 | +// It starts out in plain text mode, | |
| 30 | +# use the control below to load and apply a mode | |
| 31 | + "you'll see the highlighting of" this text /*change*/. | |
| 32 | +</textarea></form> | |
| 33 | +<p><input type=text value=javascript id=mode> <button type=button onclick="change()">change mode</button></p> | |
| 34 | + | |
| 35 | + <script> | |
| 36 | +CodeMirror.modeURL = "../mode/%N/%N.js"; | |
| 37 | +var editor = CodeMirror.fromTextArea(document.getElementById("code"), { | |
| 38 | + lineNumbers: true | |
| 39 | +}); | |
| 40 | +var modeInput = document.getElementById("mode"); | |
| 41 | +CodeMirror.on(modeInput, "keypress", function(e) { | |
| 42 | + if (e.keyCode == 13) change(); | |
| 43 | +}); | |
| 44 | +function change() { | |
| 45 | + editor.setOption("mode", modeInput.value); | |
| 46 | + CodeMirror.autoLoadMode(editor, modeInput.value); | |
| 47 | +} | |
| 48 | +</script> | |
| 49 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,52 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Breakpoint Demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<script src="../lib/codemirror.js"></script> | |
| 9 | +<script src="../mode/javascript/javascript.js"></script> | |
| 10 | +<style type="text/css"> | |
| 11 | + .breakpoints {width: .8em;} | |
| 12 | + .breakpoint { color: #822; } | |
| 13 | + .CodeMirror {border: 1px solid #aaa;} | |
| 14 | + </style> | |
| 15 | +<div id=nav> | |
| 16 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 17 | + | |
| 18 | + <ul> | |
| 19 | + <li><a href="../index.html">Home</a> | |
| 20 | + <li><a href="../doc/manual.html">Manual</a> | |
| 21 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 22 | + </ul> | |
| 23 | + <ul> | |
| 24 | + <li><a class=active href="#">Breakpoint</a> | |
| 25 | + </ul> | |
| 26 | +</div> | |
| 27 | + | |
| 28 | +<article> | |
| 29 | +<h2>Breakpoint Demo</h2> | |
| 30 | +<form><textarea id="code" name="code"> | |
| 31 | +var editor = CodeMirror.fromTextArea(document.getElementById("code"), { | |
| 32 | + lineNumbers: true, | |
| 33 | + gutters: ["CodeMirror-linenumbers", "breakpoints"] | |
| 34 | +}); | |
| 35 | +editor.on("gutterClick", function(cm, n) { | |
| 36 | + var info = cm.lineInfo(n); | |
| 37 | + cm.setGutterMarker(n, "breakpoints", info.gutterMarkers ? null : makeMarker()); | |
| 38 | +}); | |
| 39 | + | |
| 40 | +function makeMarker() { | |
| 41 | + var marker = document.createElement("div"); | |
| 42 | + marker.style.color = "#822"; | |
| 43 | + marker.innerHTML = "●"; | |
| 44 | + return marker; | |
| 45 | +} | |
| 46 | +</textarea></form> | |
| 47 | + | |
| 48 | +<p>Click the line-number gutter to add or remove 'breakpoints'.</p> | |
| 49 | + | |
| 50 | + <script>eval(document.getElementById("code").value);</script> | |
| 51 | + | |
| 52 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,52 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Selection Marking Demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<script src="../lib/codemirror.js"></script> | |
| 9 | +<script src="../addon/search/searchcursor.js"></script> | |
| 10 | +<script src="../addon/selection/mark-selection.js"></script> | |
| 11 | +<style type="text/css"> | |
| 12 | + .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;} | |
| 13 | + .CodeMirror-selected { background-color: blue !important; } | |
| 14 | + .CodeMirror-selectedtext { color: white; } | |
| 15 | + .styled-background { background-color: #ff7; } | |
| 16 | + </style> | |
| 17 | +<div id=nav> | |
| 18 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 19 | + | |
| 20 | + <ul> | |
| 21 | + <li><a href="../index.html">Home</a> | |
| 22 | + <li><a href="../doc/manual.html">Manual</a> | |
| 23 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 24 | + </ul> | |
| 25 | + <ul> | |
| 26 | + <li><a class=active href="#">Selection Marking</a> | |
| 27 | + </ul> | |
| 28 | +</div> | |
| 29 | + | |
| 30 | +<article> | |
| 31 | +<h2>Selection Marking Demo</h2> | |
| 32 | +<form><textarea id="code" name="code"> | |
| 33 | +Select something from here. You'll see that the selection's foreground | |
| 34 | +color changes to white! Since, by default, CodeMirror only puts an | |
| 35 | +independent "marker" layer behind the text, you'll need something like | |
| 36 | +this to change its colour. | |
| 37 | + | |
| 38 | +Also notice that turning this addon on (with the default style) allows | |
| 39 | +you to safely give text a background color without screwing up the | |
| 40 | +visibility of the selection.</textarea></form> | |
| 41 | + | |
| 42 | + <script> | |
| 43 | +var editor = CodeMirror.fromTextArea(document.getElementById("code"), { | |
| 44 | + lineNumbers: true, | |
| 45 | + styleSelectedText: true | |
| 46 | +}); | |
| 47 | +editor.markText({line: 6, ch: 26}, {line: 6, ch: 42}, {className: "styled-background"}); | |
| 48 | +</script> | |
| 49 | + | |
| 50 | + <p>Simple addon to easily mark (and style) selected text. <a href="../doc/manual.html#addon_mark-selection">Docs</a>.</p> | |
| 51 | + | |
| 52 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,47 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Match Highlighter Demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<script src="../lib/codemirror.js"></script> | |
| 9 | +<script src="../addon/search/searchcursor.js"></script> | |
| 10 | +<script src="../addon/search/match-highlighter.js"></script> | |
| 11 | +<style type="text/css"> | |
| 12 | + .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;} | |
| 13 | + .CodeMirror-focused .cm-matchhighlight { | |
| 14 | + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFklEQVQI12NgYGBgkKzc8x9CMDAwAAAmhwSbidEoSQAAAABJRU5ErkJggg==); | |
| 15 | + background-position: bottom; | |
| 16 | + background-repeat: repeat-x; | |
| 17 | + } | |
| 18 | + </style> | |
| 19 | +<div id=nav> | |
| 20 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 21 | + | |
| 22 | + <ul> | |
| 23 | + <li><a href="../index.html">Home</a> | |
| 24 | + <li><a href="../doc/manual.html">Manual</a> | |
| 25 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 26 | + </ul> | |
| 27 | + <ul> | |
| 28 | + <li><a class=active href="#">Match Highlighter</a> | |
| 29 | + </ul> | |
| 30 | +</div> | |
| 31 | + | |
| 32 | +<article> | |
| 33 | +<h2>Match Highlighter Demo</h2> | |
| 34 | +<form><textarea id="code" name="code">Select this text: hardToSpotVar | |
| 35 | + And everywhere else in your code where hardToSpotVar appears will automatically illuminate. | |
| 36 | +Give it a try! No more hardToSpotVars.</textarea></form> | |
| 37 | + | |
| 38 | + <script> | |
| 39 | +var editor = CodeMirror.fromTextArea(document.getElementById("code"), { | |
| 40 | + lineNumbers: true, | |
| 41 | + highlightSelectionMatches: {showToken: /\w/} | |
| 42 | +}); | |
| 43 | +</script> | |
| 44 | + | |
| 45 | + <p>Search and highlight occurences of the selected text.</p> | |
| 46 | + | |
| 47 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,48 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Tag Matcher Demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<script src="../lib/codemirror.js"></script> | |
| 9 | +<script src="../addon/fold/xml-fold.js"></script> | |
| 10 | +<script src="../addon/edit/matchtags.js"></script> | |
| 11 | +<script src="../mode/xml/xml.js"></script> | |
| 12 | +<style type="text/css"> | |
| 13 | + .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;} | |
| 14 | + </style> | |
| 15 | +<div id=nav> | |
| 16 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 17 | + | |
| 18 | + <ul> | |
| 19 | + <li><a href="../index.html">Home</a> | |
| 20 | + <li><a href="../doc/manual.html">Manual</a> | |
| 21 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 22 | + </ul> | |
| 23 | + <ul> | |
| 24 | + <li><a class=active href="#">Tag Matcher</a> | |
| 25 | + </ul> | |
| 26 | +</div> | |
| 27 | + | |
| 28 | +<article> | |
| 29 | +<h2>Tag Matcher Demo</h2> | |
| 30 | + | |
| 31 | + | |
| 32 | + <div id="editor"></div> | |
| 33 | + | |
| 34 | + <script> | |
| 35 | +window.onload = function() { | |
| 36 | + editor = CodeMirror(document.getElementById("editor"), { | |
| 37 | + value: "<html>\n " + document.documentElement.innerHTML + "\n</html>", | |
| 38 | + mode: "text/html", | |
| 39 | + matchTags: {bothTags: true}, | |
| 40 | + extraKeys: {"Ctrl-J": "toMatchingTag"} | |
| 41 | + }); | |
| 42 | +}; | |
| 43 | + </script> | |
| 44 | + | |
| 45 | + <p>Put the cursor on or inside a pair of tags to highlight them. | |
| 46 | + Press Ctrl-J to jump to the tag that matches the one under the | |
| 47 | + cursor.</p> | |
| 48 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,107 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: merge view demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel=stylesheet href="../lib/codemirror.css"> | |
| 8 | +<link rel=stylesheet href="../addon/merge/merge.css"> | |
| 9 | +<script src="../lib/codemirror.js"></script> | |
| 10 | +<script src="../mode/xml/xml.js"></script> | |
| 11 | +<script src="//cdnjs.cloudflare.com/ajax/libs/diff_match_patch/20121119/diff_match_patch.js"></script> | |
| 12 | +<script src="../addon/merge/merge.js"></script> | |
| 13 | +<style> | |
| 14 | + .CodeMirror { line-height: 1.2; } | |
| 15 | + span.clicky { | |
| 16 | + cursor: pointer; | |
| 17 | + background: #d70; | |
| 18 | + color: white; | |
| 19 | + padding: 0 3px; | |
| 20 | + border-radius: 3px; | |
| 21 | + } | |
| 22 | + </style> | |
| 23 | +<div id=nav> | |
| 24 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 25 | + | |
| 26 | + <ul> | |
| 27 | + <li><a href="../index.html">Home</a> | |
| 28 | + <li><a href="../doc/manual.html">Manual</a> | |
| 29 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 30 | + </ul> | |
| 31 | + <ul> | |
| 32 | + <li><a class=active href="#">merge view</a> | |
| 33 | + </ul> | |
| 34 | +</div> | |
| 35 | + | |
| 36 | +<article> | |
| 37 | +<h2>merge view demo</h2> | |
| 38 | + | |
| 39 | + | |
| 40 | +<div id=view></div> | |
| 41 | + | |
| 42 | +<p>The <a href="../doc/manual.html#addon_merge"><code>merge</code></a> | |
| 43 | +addon provides an interface for displaying and merging diffs, | |
| 44 | +either <span class=clicky onclick="initUI(2)">two-way</span> | |
| 45 | +or <span class=clicky onclick="initUI(3)">three-way</span>. The left | |
| 46 | +(or center) pane is editable, and the differences with the other | |
| 47 | +pane(s) are <span class=clicky onclick="toggleDifferences()">optionally</span> shown live as you edit it.</p> | |
| 48 | + | |
| 49 | +<p>This addon depends on | |
| 50 | +the <a href="https://code.google.com/p/google-diff-match-patch/">google-diff-match-patch</a> | |
| 51 | +library to compute the diffs.</p> | |
| 52 | + | |
| 53 | +<script> | |
| 54 | +var value, orig1, orig2, dv, hilight= true; | |
| 55 | +function initUI(panes) { | |
| 56 | + if (value == null) return; | |
| 57 | + var target = document.getElementById("view"); | |
| 58 | + target.innerHTML = ""; | |
| 59 | + dv = CodeMirror.MergeView(target, { | |
| 60 | + value: value, | |
| 61 | + origLeft: panes == 3 ? orig1 : null, | |
| 62 | + orig: orig2, | |
| 63 | + lineNumbers: true, | |
| 64 | + mode: "text/html", | |
| 65 | + highlightDifferences: hilight | |
| 66 | + }); | |
| 67 | +} | |
| 68 | + | |
| 69 | +function toggleDifferences() { | |
| 70 | + dv.setShowDifferences(hilight = !hilight); | |
| 71 | +} | |
| 72 | + | |
| 73 | +window.onload = function() { | |
| 74 | + value = document.documentElement.innerHTML; | |
| 75 | + orig1 = value.replace(/\.\.\//g, "codemirror/").replace("yellow", "orange"); | |
| 76 | + orig2 = value.replace(/\u003cscript/g, "\u003cscript type=text/javascript ") | |
| 77 | + .replace("white", "purple;\n font: comic sans;\n text-decoration: underline;\n height: 15em"); | |
| 78 | + initUI(2); | |
| 79 | +}; | |
| 80 | + | |
| 81 | +function mergeViewHeight(mergeView) { | |
| 82 | + function editorHeight(editor) { | |
| 83 | + if (!editor) return 0; | |
| 84 | + return editor.getScrollInfo().height; | |
| 85 | + } | |
| 86 | + return Math.max(editorHeight(mergeView.leftOriginal()), | |
| 87 | + editorHeight(mergeView.editor()), | |
| 88 | + editorHeight(mergeView.rightOriginal())); | |
| 89 | +} | |
| 90 | + | |
| 91 | +function resize(mergeView) { | |
| 92 | + var height = mergeViewHeight(mergeView); | |
| 93 | + for(;;) { | |
| 94 | + if (mergeView.leftOriginal()) | |
| 95 | + mergeView.leftOriginal().setSize(null, height); | |
| 96 | + mergeView.editor().setSize(null, height); | |
| 97 | + if (mergeView.rightOriginal()) | |
| 98 | + mergeView.rightOriginal().setSize(null, height); | |
| 99 | + | |
| 100 | + var newHeight = mergeViewHeight(mergeView); | |
| 101 | + if (newHeight >= height) break; | |
| 102 | + else height = newHeight; | |
| 103 | + } | |
| 104 | + mergeView.wrap.style.height = height + "px"; | |
| 105 | +} | |
| 106 | +</script> | |
| 107 | +</article> | ... | ... |
| ... | ... | @@ -0,0 +1,75 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Multiplexing Parser Demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<script src="../lib/codemirror.js"></script> | |
| 9 | +<script src="../addon/mode/multiplex.js"></script> | |
| 10 | +<script src="../mode/xml/xml.js"></script> | |
| 11 | +<style type="text/css"> | |
| 12 | + .CodeMirror {border: 1px solid black;} | |
| 13 | + .cm-delimit {color: #fa4;} | |
| 14 | + </style> | |
| 15 | +<div id=nav> | |
| 16 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 17 | + | |
| 18 | + <ul> | |
| 19 | + <li><a href="../index.html">Home</a> | |
| 20 | + <li><a href="../doc/manual.html">Manual</a> | |
| 21 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 22 | + </ul> | |
| 23 | + <ul> | |
| 24 | + <li><a class=active href="#">Multiplexing Parser</a> | |
| 25 | + </ul> | |
| 26 | +</div> | |
| 27 | + | |
| 28 | +<article> | |
| 29 | +<h2>Multiplexing Parser Demo</h2> | |
| 30 | +<form><textarea id="code" name="code"> | |
| 31 | +<html> | |
| 32 | + <body style="<<magic>>"> | |
| 33 | + <h1><< this is not <html >></h1> | |
| 34 | + << | |
| 35 | + multiline | |
| 36 | + not html | |
| 37 | + at all : &amp; <link/> | |
| 38 | + >> | |
| 39 | + <p>this is html again</p> | |
| 40 | + </body> | |
| 41 | +</html> | |
| 42 | +</textarea></form> | |
| 43 | + | |
| 44 | + <script> | |
| 45 | +CodeMirror.defineMode("demo", function(config) { | |
| 46 | + return CodeMirror.multiplexingMode( | |
| 47 | + CodeMirror.getMode(config, "text/html"), | |
| 48 | + {open: "<<", close: ">>", | |
| 49 | + mode: CodeMirror.getMode(config, "text/plain"), | |
| 50 | + delimStyle: "delimit"} | |
| 51 | + // .. more multiplexed styles can follow here | |
| 52 | + ); | |
| 53 | +}); | |
| 54 | +var editor = CodeMirror.fromTextArea(document.getElementById("code"), { | |
| 55 | + mode: "demo", | |
| 56 | + lineNumbers: true, | |
| 57 | + lineWrapping: true | |
| 58 | +}); | |
| 59 | +</script> | |
| 60 | + | |
| 61 | + <p>Demonstration of a multiplexing mode, which, at certain | |
| 62 | + boundary strings, switches to one or more inner modes. The out | |
| 63 | + (HTML) mode does not get fed the content of the <code><< | |
| 64 | + >></code> blocks. See | |
| 65 | + the <a href="../doc/manual.html#addon_multiplex">manual</a> and | |
| 66 | + the <a href="../addon/mode/multiplex.js">source</a> for more | |
| 67 | + information.</p> | |
| 68 | + | |
| 69 | + <p> | |
| 70 | + <strong>Parsing/Highlighting Tests:</strong> | |
| 71 | + <a href="../test/index.html#multiplexing_*">normal</a>, | |
| 72 | + <a href="../test/index.html#verbose,multiplexing_*">verbose</a>. | |
| 73 | + </p> | |
| 74 | + | |
| 75 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,68 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Overlay Parser Demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<script src="../lib/codemirror.js"></script> | |
| 9 | +<script src="../addon/mode/overlay.js"></script> | |
| 10 | +<script src="../mode/xml/xml.js"></script> | |
| 11 | +<style type="text/css"> | |
| 12 | + .CodeMirror {border: 1px solid black;} | |
| 13 | + .cm-mustache {color: #0ca;} | |
| 14 | +</style> | |
| 15 | +<div id=nav> | |
| 16 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 17 | + | |
| 18 | + <ul> | |
| 19 | + <li><a href="../index.html">Home</a> | |
| 20 | + <li><a href="../doc/manual.html">Manual</a> | |
| 21 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 22 | + </ul> | |
| 23 | + <ul> | |
| 24 | + <li><a class=active href="#">Overlay Parser</a> | |
| 25 | + </ul> | |
| 26 | +</div> | |
| 27 | + | |
| 28 | +<article> | |
| 29 | +<h2>Overlay Parser Demo</h2> | |
| 30 | +<form><textarea id="code" name="code"> | |
| 31 | +<html> | |
| 32 | + <body> | |
| 33 | + <h1>{{title}}</h1> | |
| 34 | + <p>These are links to {{things}}:</p> | |
| 35 | + <ul>{{#links}} | |
| 36 | + <li><a href="{{url}}">{{text}}</a></li> | |
| 37 | + {{/links}}</ul> | |
| 38 | + </body> | |
| 39 | +</html> | |
| 40 | +</textarea></form> | |
| 41 | + | |
| 42 | + <script> | |
| 43 | +CodeMirror.defineMode("mustache", function(config, parserConfig) { | |
| 44 | + var mustacheOverlay = { | |
| 45 | + token: function(stream, state) { | |
| 46 | + var ch; | |
| 47 | + if (stream.match("{{")) { | |
| 48 | + while ((ch = stream.next()) != null) | |
| 49 | + if (ch == "}" && stream.next() == "}") break; | |
| 50 | + stream.eat("}"); | |
| 51 | + return "mustache"; | |
| 52 | + } | |
| 53 | + while (stream.next() != null && !stream.match("{{", false)) {} | |
| 54 | + return null; | |
| 55 | + } | |
| 56 | + }; | |
| 57 | + return CodeMirror.overlayMode(CodeMirror.getMode(config, parserConfig.backdrop || "text/html"), mustacheOverlay); | |
| 58 | +}); | |
| 59 | +var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: "mustache"}); | |
| 60 | +</script> | |
| 61 | + | |
| 62 | + <p>Demonstration of a mode that parses HTML, highlighting | |
| 63 | + the <a href="http://mustache.github.com/">Mustache</a> templating | |
| 64 | + directives inside of it by using the code | |
| 65 | + in <a href="../addon/mode/overlay.js"><code>overlay.js</code></a>. View | |
| 66 | + source to see the 15 lines of code needed to accomplish this.</p> | |
| 67 | + | |
| 68 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,45 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Placeholder demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<script src="../lib/codemirror.js"></script> | |
| 9 | +<script src="../addon/display/placeholder.js"></script> | |
| 10 | +<style type="text/css"> | |
| 11 | + .CodeMirror { border: 1px solid silver; } | |
| 12 | + .CodeMirror-empty { outline: 1px solid #c22; } | |
| 13 | + .CodeMirror-empty.CodeMirror-focused { outline: none; } | |
| 14 | + .CodeMirror pre.CodeMirror-placeholder { color: #999; } | |
| 15 | + </style> | |
| 16 | +<div id=nav> | |
| 17 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 18 | + | |
| 19 | + <ul> | |
| 20 | + <li><a href="../index.html">Home</a> | |
| 21 | + <li><a href="../doc/manual.html">Manual</a> | |
| 22 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 23 | + </ul> | |
| 24 | + <ul> | |
| 25 | + <li><a class=active href="#">Placeholder</a> | |
| 26 | + </ul> | |
| 27 | +</div> | |
| 28 | + | |
| 29 | +<article> | |
| 30 | +<h2>Placeholder demo</h2> | |
| 31 | +<form><textarea id="code" name="code" placeholder="Code goes here..."></textarea></form> | |
| 32 | + | |
| 33 | + <p>The <a href="../doc/manual.html#addon_placeholder">placeholder</a> | |
| 34 | + plug-in adds an option <code>placeholder</code> that can be set to | |
| 35 | + make text appear in the editor when it is empty and not focused. | |
| 36 | + If the source textarea has a <code>placeholder</code> attribute, | |
| 37 | + it will automatically be inherited.</p> | |
| 38 | + | |
| 39 | + <script> | |
| 40 | + var editor = CodeMirror.fromTextArea(document.getElementById("code"), { | |
| 41 | + lineNumbers: true | |
| 42 | + }); | |
| 43 | + </script> | |
| 44 | + | |
| 45 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,87 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: HTML5 preview</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel=stylesheet href=../lib/codemirror.css> | |
| 8 | +<script src=../lib/codemirror.js></script> | |
| 9 | +<script src=../mode/xml/xml.js></script> | |
| 10 | +<script src=../mode/javascript/javascript.js></script> | |
| 11 | +<script src=../mode/css/css.js></script> | |
| 12 | +<script src=../mode/htmlmixed/htmlmixed.js></script> | |
| 13 | +<style type=text/css> | |
| 14 | + .CodeMirror { | |
| 15 | + float: left; | |
| 16 | + width: 50%; | |
| 17 | + border: 1px solid black; | |
| 18 | + } | |
| 19 | + iframe { | |
| 20 | + width: 49%; | |
| 21 | + float: left; | |
| 22 | + height: 300px; | |
| 23 | + border: 1px solid black; | |
| 24 | + border-left: 0px; | |
| 25 | + } | |
| 26 | + </style> | |
| 27 | +<div id=nav> | |
| 28 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 29 | + | |
| 30 | + <ul> | |
| 31 | + <li><a href="../index.html">Home</a> | |
| 32 | + <li><a href="../doc/manual.html">Manual</a> | |
| 33 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 34 | + </ul> | |
| 35 | + <ul> | |
| 36 | + <li><a class=active href="#">HTML5 preview</a> | |
| 37 | + </ul> | |
| 38 | +</div> | |
| 39 | + | |
| 40 | +<article> | |
| 41 | +<h2>HTML5 preview</h2> | |
| 42 | + | |
| 43 | + <textarea id=code name=code> | |
| 44 | +<!doctype html> | |
| 45 | +<html> | |
| 46 | + <head> | |
| 47 | + <meta charset=utf-8> | |
| 48 | + <title>HTML5 canvas demo</title> | |
| 49 | + <style>p {font-family: monospace;}</style> | |
| 50 | + </head> | |
| 51 | + <body> | |
| 52 | + <p>Canvas pane goes here:</p> | |
| 53 | + <canvas id=pane width=300 height=200></canvas> | |
| 54 | + <script> | |
| 55 | + var canvas = document.getElementById('pane'); | |
| 56 | + var context = canvas.getContext('2d'); | |
| 57 | + | |
| 58 | + context.fillStyle = 'rgb(250,0,0)'; | |
| 59 | + context.fillRect(10, 10, 55, 50); | |
| 60 | + | |
| 61 | + context.fillStyle = 'rgba(0, 0, 250, 0.5)'; | |
| 62 | + context.fillRect(30, 30, 55, 50); | |
| 63 | + </script> | |
| 64 | + </body> | |
| 65 | +</html></textarea> | |
| 66 | + <iframe id=preview></iframe> | |
| 67 | + <script> | |
| 68 | + var delay; | |
| 69 | + // Initialize CodeMirror editor with a nice html5 canvas demo. | |
| 70 | + var editor = CodeMirror.fromTextArea(document.getElementById('code'), { | |
| 71 | + mode: 'text/html' | |
| 72 | + }); | |
| 73 | + editor.on("change", function() { | |
| 74 | + clearTimeout(delay); | |
| 75 | + delay = setTimeout(updatePreview, 300); | |
| 76 | + }); | |
| 77 | + | |
| 78 | + function updatePreview() { | |
| 79 | + var previewFrame = document.getElementById('preview'); | |
| 80 | + var preview = previewFrame.contentDocument || previewFrame.contentWindow.document; | |
| 81 | + preview.open(); | |
| 82 | + preview.write(editor.getValue()); | |
| 83 | + preview.close(); | |
| 84 | + } | |
| 85 | + setTimeout(updatePreview, 300); | |
| 86 | + </script> | |
| 87 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,52 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<head> | |
| 4 | + <title>CodeMirror: HTML completion demo</title> | |
| 5 | + <meta charset="utf-8"/> | |
| 6 | + <link rel=stylesheet href="../doc/docs.css"> | |
| 7 | + | |
| 8 | + <link rel="stylesheet" href="../lib/codemirror.css"> | |
| 9 | + <link rel="stylesheet" href="../addon/hint/show-hint.css"> | |
| 10 | + <script src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.1.14/require.min.js"></script> | |
| 11 | + <style type="text/css"> | |
| 12 | + .CodeMirror {border-top: 1px solid #888; border-bottom: 1px solid #888;} | |
| 13 | + </style> | |
| 14 | +</head> | |
| 15 | + | |
| 16 | +<body> | |
| 17 | + <div id=nav> | |
| 18 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 19 | + <ul> | |
| 20 | + <li><a href="../index.html">Home</a> | |
| 21 | + <li><a href="../doc/manual.html">Manual</a> | |
| 22 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 23 | + </ul> | |
| 24 | + <ul> | |
| 25 | + <li><a class=active href="#">HTML completion</a> | |
| 26 | + </ul> | |
| 27 | + </div> | |
| 28 | + | |
| 29 | + <article> | |
| 30 | + <h2>RequireJS module loading demo</h2> | |
| 31 | + | |
| 32 | + <p>This demo does the same thing as | |
| 33 | + the <a href="html5complete.html">HTML5 completion demo</a>, but | |
| 34 | + loads its dependencies | |
| 35 | + with <a href="http://requirejs.org/">Require.js</a>, rather than | |
| 36 | + explicitly. Press <strong>ctrl-space</strong> to activate | |
| 37 | + completion.</p> | |
| 38 | + | |
| 39 | + <div id="code"></div> | |
| 40 | + | |
| 41 | + <script type="text/javascript"> | |
| 42 | + require(["../lib/codemirror", "../mode/htmlmixed/htmlmixed", | |
| 43 | + "../addon/hint/show-hint", "../addon/hint/html-hint"], function(CodeMirror) { | |
| 44 | + editor = CodeMirror(document.getElementById("code"), { | |
| 45 | + mode: "text/html", | |
| 46 | + extraKeys: {"Ctrl-Space": "autocomplete"}, | |
| 47 | + value: document.documentElement.innerHTML | |
| 48 | + }); | |
| 49 | + }); | |
| 50 | + </script> | |
| 51 | + </article> | |
| 52 | +</body> | ... | ... |
| ... | ... | @@ -0,0 +1,58 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Autoresize Demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<script src="../lib/codemirror.js"></script> | |
| 9 | +<script src="../mode/css/css.js"></script> | |
| 10 | +<style type="text/css"> | |
| 11 | + .CodeMirror { | |
| 12 | + border: 1px solid #eee; | |
| 13 | + height: auto; | |
| 14 | + } | |
| 15 | + .CodeMirror-scroll { | |
| 16 | + overflow-y: hidden; | |
| 17 | + overflow-x: auto; | |
| 18 | + } | |
| 19 | + </style> | |
| 20 | +<div id=nav> | |
| 21 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 22 | + | |
| 23 | + <ul> | |
| 24 | + <li><a href="../index.html">Home</a> | |
| 25 | + <li><a href="../doc/manual.html">Manual</a> | |
| 26 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 27 | + </ul> | |
| 28 | + <ul> | |
| 29 | + <li><a class=active href="#">Autoresize</a> | |
| 30 | + </ul> | |
| 31 | +</div> | |
| 32 | + | |
| 33 | +<article> | |
| 34 | +<h2>Autoresize Demo</h2> | |
| 35 | +<form><textarea id="code" name="code"> | |
| 36 | +.CodeMirror { | |
| 37 | + border: 1px solid #eee; | |
| 38 | + height: auto; | |
| 39 | +} | |
| 40 | +.CodeMirror-scroll { | |
| 41 | + overflow-y: hidden; | |
| 42 | + overflow-x: auto; | |
| 43 | +} | |
| 44 | +</textarea></form> | |
| 45 | + | |
| 46 | +<p>By setting a few CSS properties, and giving | |
| 47 | +the <a href="../doc/manual.html#option_viewportMargin"><code>viewportMargin</code></a> | |
| 48 | +a value of <code>Infinity</code>, CodeMirror can be made to | |
| 49 | +automatically resize to fit its content.</p> | |
| 50 | + | |
| 51 | + <script> | |
| 52 | + var editor = CodeMirror.fromTextArea(document.getElementById("code"), { | |
| 53 | + lineNumbers: true, | |
| 54 | + viewportMargin: Infinity | |
| 55 | + }); | |
| 56 | + </script> | |
| 57 | + | |
| 58 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,49 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Ruler Demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<script src="../lib/codemirror.js"></script> | |
| 9 | +<script src="../addon/display/rulers.js"></script> | |
| 10 | +<style type="text/css"> | |
| 11 | + .CodeMirror {border-top: 1px solid #888; border-bottom: 1px solid #888;} | |
| 12 | +</style> | |
| 13 | +<div id=nav> | |
| 14 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 15 | + | |
| 16 | + <ul> | |
| 17 | + <li><a href="../index.html">Home</a> | |
| 18 | + <li><a href="../doc/manual.html">Manual</a> | |
| 19 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 20 | + </ul> | |
| 21 | + <ul> | |
| 22 | + <li><a class=active href="#">Ruler demo</a> | |
| 23 | + </ul> | |
| 24 | +</div> | |
| 25 | + | |
| 26 | +<article> | |
| 27 | +<h2>Ruler Demo</h2> | |
| 28 | + | |
| 29 | +<script type="text/javascript"> | |
| 30 | + var nums = "0123456789", space = " "; | |
| 31 | + var colors = ["#fcc", "#f5f577", "#cfc", "#aff", "#ccf", "#fcf"]; | |
| 32 | + var rulers = [], value = ""; | |
| 33 | + for (var i = 1; i <= 6; i++) { | |
| 34 | + rulers.push({color: colors[i], column: i * 10, lineStyle: "dashed"}); | |
| 35 | + for (var j = 1; j < i; j++) value += space; | |
| 36 | + value += nums + "\n"; | |
| 37 | + } | |
| 38 | + var editor = CodeMirror(document.body.lastChild, { | |
| 39 | + rulers: rulers, | |
| 40 | + value: value + value + value, | |
| 41 | + lineNumbers: true | |
| 42 | +}); | |
| 43 | +</script> | |
| 44 | + | |
| 45 | +<p>Demonstration of | |
| 46 | +the <a href="../doc/manual.html#addon_rulers">rulers</a> addon, which | |
| 47 | +displays vertical lines at given column offsets.</p> | |
| 48 | + | |
| 49 | +</article> | ... | ... |
| ... | ... | @@ -0,0 +1,62 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Mode Runner Demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<script src="../lib/codemirror.js"></script> | |
| 9 | +<script src="../addon/runmode/runmode.js"></script> | |
| 10 | +<script src="../mode/xml/xml.js"></script> | |
| 11 | +<div id=nav> | |
| 12 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 13 | + | |
| 14 | + <ul> | |
| 15 | + <li><a href="../index.html">Home</a> | |
| 16 | + <li><a href="../doc/manual.html">Manual</a> | |
| 17 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 18 | + </ul> | |
| 19 | + <ul> | |
| 20 | + <li><a class=active href="#">Mode Runner</a> | |
| 21 | + </ul> | |
| 22 | +</div> | |
| 23 | + | |
| 24 | +<article> | |
| 25 | +<h2>Mode Runner Demo</h2> | |
| 26 | + | |
| 27 | + | |
| 28 | + <textarea id="code" style="width: 90%; height: 7em; border: 1px solid black; padding: .2em .4em;"> | |
| 29 | +<foobar> | |
| 30 | + <blah>Enter your xml here and press the button below to display | |
| 31 | + it as highlighted by the CodeMirror XML mode</blah> | |
| 32 | + <tag2 foo="2" bar="&quot;bar&quot;"/> | |
| 33 | +</foobar></textarea><br> | |
| 34 | + <button onclick="doHighlight();">Highlight!</button> | |
| 35 | + <pre id="output" class="cm-s-default"></pre> | |
| 36 | + | |
| 37 | + <script> | |
| 38 | +function doHighlight() { | |
| 39 | + CodeMirror.runMode(document.getElementById("code").value, "application/xml", | |
| 40 | + document.getElementById("output")); | |
| 41 | +} | |
| 42 | +</script> | |
| 43 | + | |
| 44 | + <p>Running a CodeMirror mode outside of the editor. | |
| 45 | + The <code>CodeMirror.runMode</code> function, defined | |
| 46 | + in <code><a href="../addon/runmode/runmode.js">lib/runmode.js</a></code> takes the following arguments:</p> | |
| 47 | + | |
| 48 | + <dl> | |
| 49 | + <dt><code>text (string)</code></dt> | |
| 50 | + <dd>The document to run through the highlighter.</dd> | |
| 51 | + <dt><code>mode (<a href="../doc/manual.html#option_mode">mode spec</a>)</code></dt> | |
| 52 | + <dd>The mode to use (must be loaded as normal).</dd> | |
| 53 | + <dt><code>output (function or DOM node)</code></dt> | |
| 54 | + <dd>If this is a function, it will be called for each token with | |
| 55 | + two arguments, the token's text and the token's style class (may | |
| 56 | + be <code>null</code> for unstyled tokens). If it is a DOM node, | |
| 57 | + the tokens will be converted to <code>span</code> elements as in | |
| 58 | + an editor, and inserted into the node | |
| 59 | + (through <code>innerHTML</code>).</dd> | |
| 60 | + </dl> | |
| 61 | + | |
| 62 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,87 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Search/Replace Demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<link rel="stylesheet" href="../addon/dialog/dialog.css"> | |
| 9 | +<script src="../lib/codemirror.js"></script> | |
| 10 | +<script src="../mode/xml/xml.js"></script> | |
| 11 | +<script src="../addon/dialog/dialog.js"></script> | |
| 12 | +<script src="../addon/search/searchcursor.js"></script> | |
| 13 | +<script src="../addon/search/search.js"></script> | |
| 14 | +<style type="text/css"> | |
| 15 | + .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;} | |
| 16 | + dt {font-family: monospace; color: #666;} | |
| 17 | + </style> | |
| 18 | +<div id=nav> | |
| 19 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 20 | + | |
| 21 | + <ul> | |
| 22 | + <li><a href="../index.html">Home</a> | |
| 23 | + <li><a href="../doc/manual.html">Manual</a> | |
| 24 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 25 | + </ul> | |
| 26 | + <ul> | |
| 27 | + <li><a class=active href="#">Search/Replace</a> | |
| 28 | + </ul> | |
| 29 | +</div> | |
| 30 | + | |
| 31 | +<article> | |
| 32 | +<h2>Search/Replace Demo</h2> | |
| 33 | +<form><textarea id="code" name="code"> | |
| 34 | +<dl> | |
| 35 | + <dt id="option_indentWithTabs"><code><strong>indentWithTabs</strong>: boolean</code></dt> | |
| 36 | + <dd>Whether, when indenting, the first N*<code>tabSize</code> | |
| 37 | + spaces should be replaced by N tabs. Default is false.</dd> | |
| 38 | + | |
| 39 | + <dt id="option_electricChars"><code><strong>electricChars</strong>: boolean</code></dt> | |
| 40 | + <dd>Configures whether the editor should re-indent the current | |
| 41 | + line when a character is typed that might change its proper | |
| 42 | + indentation (only works if the mode supports indentation). | |
| 43 | + Default is true.</dd> | |
| 44 | + | |
| 45 | + <dt id="option_specialChars"><code><strong>specialChars</strong>: RegExp</code></dt> | |
| 46 | + <dd>A regular expression used to determine which characters | |
| 47 | + should be replaced by a | |
| 48 | + special <a href="#option_specialCharPlaceholder">placeholder</a>. | |
| 49 | + Mostly useful for non-printing special characters. The default | |
| 50 | + is <code>/[\u0000-\u0019\u00ad\u200b\u2028\u2029\ufeff]/</code>.</dd> | |
| 51 | + <dt id="option_specialCharPlaceholder"><code><strong>specialCharPlaceholder</strong>: function(char) → Element</code></dt> | |
| 52 | + <dd>A function that, given a special character identified by | |
| 53 | + the <a href="#option_specialChars"><code>specialChars</code></a> | |
| 54 | + option, produces a DOM node that is used to represent the | |
| 55 | + character. By default, a red dot (<span style="color: red">•</span>) | |
| 56 | + is shown, with a title tooltip to indicate the character code.</dd> | |
| 57 | + | |
| 58 | + <dt id="option_rtlMoveVisually"><code><strong>rtlMoveVisually</strong>: boolean</code></dt> | |
| 59 | + <dd>Determines whether horizontal cursor movement through | |
| 60 | + right-to-left (Arabic, Hebrew) text is visual (pressing the left | |
| 61 | + arrow moves the cursor left) or logical (pressing the left arrow | |
| 62 | + moves to the next lower index in the string, which is visually | |
| 63 | + right in right-to-left text). The default is <code>false</code> | |
| 64 | + on Windows, and <code>true</code> on other platforms.</dd> | |
| 65 | +</dl> | |
| 66 | +</textarea></form> | |
| 67 | + | |
| 68 | + <script> | |
| 69 | +var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: "text/html", lineNumbers: true}); | |
| 70 | +</script> | |
| 71 | + | |
| 72 | + <p>Demonstration of primitive search/replace functionality. The | |
| 73 | + keybindings (which can be overridden by custom keymaps) are:</p> | |
| 74 | + <dl> | |
| 75 | + <dt>Ctrl-F / Cmd-F</dt><dd>Start searching</dd> | |
| 76 | + <dt>Ctrl-G / Cmd-G</dt><dd>Find next</dd> | |
| 77 | + <dt>Shift-Ctrl-G / Shift-Cmd-G</dt><dd>Find previous</dd> | |
| 78 | + <dt>Shift-Ctrl-F / Cmd-Option-F</dt><dd>Replace</dd> | |
| 79 | + <dt>Shift-Ctrl-R / Shift-Cmd-Option-F</dt><dd>Replace all</dd> | |
| 80 | + </dl> | |
| 81 | + <p>Searching is enabled by | |
| 82 | + including <a href="../addon/search/search.js">addon/search/search.js</a> | |
| 83 | + and <a href="../addon/search/searchcursor.js">addon/search/searchcursor.js</a>. | |
| 84 | + For good-looking input dialogs, you also want to include | |
| 85 | + <a href="../addon/dialog/dialog.js">addon/dialog/dialog.js</a> | |
| 86 | + and <a href="../addon/dialog/dialog.css">addon/dialog/dialog.css</a>.</p> | |
| 87 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,85 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Automatically derive odd wrapping behavior for your browser</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<div id=nav> | |
| 8 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 9 | + | |
| 10 | + <ul> | |
| 11 | + <li><a href="../index.html">Home</a> | |
| 12 | + <li><a href="../doc/manual.html">Manual</a> | |
| 13 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 14 | + </ul> | |
| 15 | + <ul> | |
| 16 | + <li><a class=active href="#">Automatically derive odd wrapping behavior for your browser</a> | |
| 17 | + </ul> | |
| 18 | +</div> | |
| 19 | + | |
| 20 | +<article> | |
| 21 | +<h2>Automatically derive odd wrapping behavior for your browser</h2> | |
| 22 | + | |
| 23 | + | |
| 24 | + <p>This is a hack to automatically derive | |
| 25 | + a <code>spanAffectsWrapping</code> regexp for a browser. See the | |
| 26 | + comments above that variable | |
| 27 | + in <a href="../lib/codemirror.js"><code>lib/codemirror.js</code></a> | |
| 28 | + for some more details.</p> | |
| 29 | + | |
| 30 | + <div style="white-space: pre-wrap; width: 50px;" id="area"></div> | |
| 31 | + <pre id="output"></pre> | |
| 32 | + | |
| 33 | + <script id="script"> | |
| 34 | + var a = document.getElementById("area"), bad = Object.create(null); | |
| 35 | + var chars = "a~`!@#$%^&*()-_=+}{[]\\|'\"/?.>,<:;", l = chars.length; | |
| 36 | + for (var x = 0; x < l; ++x) for (var y = 0; y < l; ++y) { | |
| 37 | + var s1 = "foooo" + chars.charAt(x), s2 = chars.charAt(y) + "br"; | |
| 38 | + a.appendChild(document.createTextNode(s1 + s2)); | |
| 39 | + var h1 = a.offsetHeight; | |
| 40 | + a.innerHTML = ""; | |
| 41 | + a.appendChild(document.createElement("span")).appendChild(document.createTextNode(s1)); | |
| 42 | + a.appendChild(document.createElement("span")).appendChild(document.createTextNode(s2)); | |
| 43 | + if (a.offsetHeight != h1) | |
| 44 | + bad[chars.charAt(x)] = (bad[chars.charAt(x)] || "") + chars.charAt(y); | |
| 45 | + a.innerHTML = ""; | |
| 46 | + } | |
| 47 | + | |
| 48 | + var re = ""; | |
| 49 | + function toREElt(str) { | |
| 50 | + if (str.length > 1) { | |
| 51 | + var invert = false; | |
| 52 | + if (str.length > chars.length * .6) { | |
| 53 | + invert = true; | |
| 54 | + var newStr = ""; | |
| 55 | + for (var i = 0; i < l; ++i) if (str.indexOf(chars.charAt(i)) == -1) newStr += chars.charAt(i); | |
| 56 | + str = newStr; | |
| 57 | + } | |
| 58 | + str = str.replace(/[\-\.\]\"\'\\\/\^a]/g, function(orig) { return orig == "a" ? "\\w" : "\\" + orig; }); | |
| 59 | + return "[" + (invert ? "^" : "") + str + "]"; | |
| 60 | + } else if (str == "a") { | |
| 61 | + return "\\w"; | |
| 62 | + } else if (/[?$*()+{}[\]\.|/\'\"]/.test(str)) { | |
| 63 | + return "\\" + str; | |
| 64 | + } else { | |
| 65 | + return str; | |
| 66 | + } | |
| 67 | + } | |
| 68 | + | |
| 69 | + var newRE = ""; | |
| 70 | + for (;;) { | |
| 71 | + var left = null; | |
| 72 | + for (var left in bad) break; | |
| 73 | + if (left == null) break; | |
| 74 | + var right = bad[left]; | |
| 75 | + delete bad[left]; | |
| 76 | + for (var other in bad) if (bad[other] == right) { | |
| 77 | + left += other; | |
| 78 | + delete bad[other]; | |
| 79 | + } | |
| 80 | + newRE += (newRE ? "|" : "") + toREElt(left) + toREElt(right); | |
| 81 | + } | |
| 82 | + | |
| 83 | + document.getElementById("output").appendChild(document.createTextNode("Your regexp is: " + (newRE || "^$"))); | |
| 84 | + </script> | |
| 85 | + </article> | ... | ... |
| ... | ... | @@ -0,0 +1,79 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Sublime Text bindings demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<link rel="stylesheet" href="../addon/fold/foldgutter.css"> | |
| 9 | +<link rel="stylesheet" href="../addon/dialog/dialog.css"> | |
| 10 | +<link rel="stylesheet" href="../theme/monokai.css"> | |
| 11 | +<script src="../lib/codemirror.js"></script> | |
| 12 | +<script src="../addon/search/searchcursor.js"></script> | |
| 13 | +<script src="../addon/search/search.js"></script> | |
| 14 | +<script src="../addon/dialog/dialog.js"></script> | |
| 15 | +<script src="../addon/edit/matchbrackets.js"></script> | |
| 16 | +<script src="../addon/edit/closebrackets.js"></script> | |
| 17 | +<script src="../addon/comment/comment.js"></script> | |
| 18 | +<script src="../addon/wrap/hardwrap.js"></script> | |
| 19 | +<script src="../addon/fold/foldcode.js"></script> | |
| 20 | +<script src="../addon/fold/brace-fold.js"></script> | |
| 21 | +<script src="../mode/javascript/javascript.js"></script> | |
| 22 | +<script src="../keymap/sublime.js"></script> | |
| 23 | +<style type="text/css"> | |
| 24 | + .CodeMirror {border-top: 1px solid #eee; border-bottom: 1px solid #eee; line-height: 1.3; height: 500px} | |
| 25 | + .CodeMirror-linenumbers { padding: 0 8px; } | |
| 26 | +</style> | |
| 27 | +<div id=nav> | |
| 28 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 29 | + | |
| 30 | + <ul> | |
| 31 | + <li><a href="../index.html">Home</a> | |
| 32 | + <li><a href="../doc/manual.html">Manual</a> | |
| 33 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 34 | + </ul> | |
| 35 | + <ul> | |
| 36 | + <li><a class=active href="#">Sublime bindings</a> | |
| 37 | + </ul> | |
| 38 | +</div> | |
| 39 | + | |
| 40 | +<article> | |
| 41 | +<h2>Sublime Text bindings demo</h2> | |
| 42 | + | |
| 43 | +<p>The <code>sublime</code> keymap defines many Sublime Text-specific | |
| 44 | +bindings for CodeMirror. See the code below for an overview.</p> | |
| 45 | + | |
| 46 | +<p>Enable the keymap by | |
| 47 | +loading <a href="../keymap/sublime.js"><code>keymap/sublime.js</code></a> | |
| 48 | +and setting | |
| 49 | +the <a href="../doc/manual.html#option_keyMap"><code>keyMap</code></a> | |
| 50 | +option to <code>"sublime"</code>.</p> | |
| 51 | + | |
| 52 | +<p>(A lot of the search functionality is still missing.) | |
| 53 | + | |
| 54 | +<script> | |
| 55 | + var value = "// The bindings defined specifically in the Sublime Text mode\nvar bindings = {\n"; | |
| 56 | + var map = CodeMirror.keyMap.sublime, mapK = CodeMirror.keyMap["sublime-Ctrl-K"]; | |
| 57 | + for (var key in map) { | |
| 58 | + if (key != "Ctrl-K" && key != "fallthrough" && (!/find/.test(map[key]) || /findUnder/.test(map[key]))) | |
| 59 | + value += " \"" + key + "\": \"" + map[key] + "\",\n"; | |
| 60 | + } | |
| 61 | + for (var key in mapK) { | |
| 62 | + if (key != "auto" && key != "nofallthrough") | |
| 63 | + value += " \"Ctrl-K " + key + "\": \"" + mapK[key] + "\",\n"; | |
| 64 | + } | |
| 65 | + value += "}\n\n// The implementation of joinLines\n"; | |
| 66 | + value += CodeMirror.commands.joinLines.toString().replace(/^function\s*\(/, "function joinLines(").replace(/\n /g, "\n") + "\n"; | |
| 67 | + var editor = CodeMirror(document.body.getElementsByTagName("article")[0], { | |
| 68 | + value: value, | |
| 69 | + lineNumbers: true, | |
| 70 | + mode: "javascript", | |
| 71 | + keyMap: "sublime", | |
| 72 | + autoCloseBrackets: true, | |
| 73 | + matchBrackets: true, | |
| 74 | + showCursorWhenSelecting: true, | |
| 75 | + theme: "monokai" | |
| 76 | + }); | |
| 77 | +</script> | |
| 78 | + | |
| 79 | +</article> | ... | ... |
| ... | ... | @@ -0,0 +1,131 @@ |
| 1 | +<!doctype html> | |
| 2 | + | |
| 3 | +<title>CodeMirror: Tern Demo</title> | |
| 4 | +<meta charset="utf-8"/> | |
| 5 | +<link rel=stylesheet href="../doc/docs.css"> | |
| 6 | + | |
| 7 | +<link rel="stylesheet" href="../lib/codemirror.css"> | |
| 8 | +<link rel="stylesheet" href="../addon/dialog/dialog.css"> | |
| 9 | +<link rel="stylesheet" href="../addon/hint/show-hint.css"> | |
| 10 | +<link rel="stylesheet" href="../addon/tern/tern.css"> | |
| 11 | +<script src="../lib/codemirror.js"></script> | |
| 12 | +<script src="../mode/javascript/javascript.js"></script> | |
| 13 | +<script src="../addon/dialog/dialog.js"></script> | |
| 14 | +<script src="../addon/hint/show-hint.js"></script> | |
| 15 | +<script src="../addon/tern/tern.js"></script> | |
| 16 | +<script src="http://marijnhaverbeke.nl/acorn/acorn.js"></script> | |
| 17 | +<script src="http://marijnhaverbeke.nl/acorn/acorn_loose.js"></script> | |
| 18 | +<script src="http://marijnhaverbeke.nl/acorn/util/walk.js"></script> | |
| 19 | +<script src="http://ternjs.net/doc/demo/polyfill.js"></script> | |
| 20 | +<script src="http://ternjs.net/lib/signal.js"></script> | |
| 21 | +<script src="http://ternjs.net/lib/tern.js"></script> | |
| 22 | +<script src="http://ternjs.net/lib/def.js"></script> | |
| 23 | +<script src="http://ternjs.net/lib/comment.js"></script> | |
| 24 | +<script src="http://ternjs.net/lib/infer.js"></script> | |
| 25 | +<script src="http://ternjs.net/plugin/doc_comment.js"></script> | |
| 26 | +<style> | |
| 27 | + .CodeMirror {border: 1px solid #ddd;} | |
| 28 | + </style> | |
| 29 | +<div id=nav> | |
| 30 | + <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a> | |
| 31 | + | |
| 32 | + <ul> | |
| 33 | + <li><a href="../index.html">Home</a> | |
| 34 | + <li><a href="../doc/manual.html">Manual</a> | |
| 35 | + <li><a href="https://github.com/marijnh/codemirror">Code</a> | |
| 36 | + </ul> | |
| 37 | + <ul> | |
| 38 | + <li><a class=active href="#">Tern</a> | |
| 39 | + </ul> | |
| 40 | +</div> | |
| 41 | + | |
| 42 | +<article> | |
| 43 | +<h2>Tern Demo</h2> | |
| 44 | +<form><textarea id="code" name="code">// Use ctrl-space to complete something | |
| 45 | +// Put the cursor in or after an expression, press ctrl-i to | |
| 46 | +// find its type | |
| 47 | + | |
| 48 | +var foo = ["array", "of", "strings"]; | |
| 49 | +var bar = foo.slice(0, 2).join("").split("a")[0]; | |
| 50 | + | |
| 51 | +// Works for locally defined types too. | |
| 52 | + | |
| 53 | +function CTor() { this.size = 10; } | |
| 54 | +CTor.prototype.hallo = "hallo"; | |
| 55 | + | |
| 56 | +var baz = new CTor; | |
| 57 | +baz. | |
| 58 | + | |
| 59 | +// You can press ctrl-q when the cursor is on a variable name to | |
| 60 | +// rename it. Try it with CTor... | |
| 61 | + | |
| 62 | +// When the cursor is in an argument list, the arguments are | |
| 63 | +// shown below the editor. | |
| 64 | + | |
| 65 | +[1].reduce( ); | |
| 66 | + | |
| 67 | +// And a little more advanced code... | |
| 68 | + | |
| 69 | +(function(exports) { | |
| 70 | + exports.randomElt = function(arr) { | |
| 71 | + return arr[Math.floor(arr.length * Math.random())]; | |
| 72 | + }; | |
| 73 | + exports.strList = "foo".split(""); | |
| 74 | + exports.intList = exports.strList.map(function(s) { return s.charCodeAt(0); }); | |
| 75 | +})(window.myMod = {}); | |
| 76 | + | |
| 77 | +var randomStr = myMod.randomElt(myMod.strList); | |
| 78 | +var randomInt = myMod.randomElt(myMod.intList); | |
| 79 | +</textarea></p> | |
| 80 | + | |
| 81 | +<p>Demonstrates integration of <a href="http://ternjs.net/">Tern</a> | |
| 82 | +and CodeMirror. The following keys are bound:</p> | |
| 83 | + | |
| 84 | +<dl> | |
| 85 | + <dt>Ctrl-Space</dt><dd>Autocomplete</dd> | |
| 86 | + <dt>Ctrl-I</dt><dd>Find type at cursor</dd> | |
| 87 | + <dt>Alt-.</dt><dd>Jump to definition (Alt-, to jump back)</dd> | |
| 88 | + <dt>Ctrl-Q</dt><dd>Rename variable</dd> | |
| 89 | + <dt>Ctrl-.</dt><dd>Select all occurrences of a variable</dd> | |
| 90 | +</dl> | |
| 91 | + | |
| 92 | +<p>Documentation is sparse for now. See the top of | |
| 93 | +the <a href="../addon/tern/tern.js">script</a> for a rough API | |
| 94 | +overview.</p> | |
| 95 | + | |
| 96 | +<script> | |
| 97 | + function getURL(url, c) { | |
| 98 | + var xhr = new XMLHttpRequest(); | |
| 99 | + xhr.open("get", url, true); | |
| 100 | + xhr.send(); | |
| 101 | + xhr.onreadystatechange = function() { | |
| 102 | + if (xhr.readyState != 4) return; | |
| 103 | + if (xhr.status < 400) return c(null, xhr.responseText); | |
| 104 | + var e = new Error(xhr.responseText || "No response"); | |
| 105 | + e.status = xhr.status; | |
| 106 | + c(e); | |
| 107 | + }; | |
| 108 | + } | |
| 109 | + | |
| 110 | + var server; | |
| 111 | + getURL("http://ternjs.net/defs/ecma5.json", function(err, code) { | |
| 112 | + if (err) throw new Error("Request for ecma5.json: " + err); | |
| 113 | + server = new CodeMirror.TernServer({defs: [JSON.parse(code)]}); | |
| 114 | + editor.setOption("extraKeys", { | |
| 115 | + "Ctrl-Space": function(cm) { server.complete(cm); }, | |
| 116 | + "Ctrl-I": function(cm) { server.showType(cm); }, | |
| 117 | + "Alt-.": function(cm) { server.jumpToDef(cm); }, | |
| 118 | + "Alt-,": function(cm) { server.jumpBack(cm); }, | |
| 119 | + "Ctrl-Q": function(cm) { server.rename(cm); }, | |
| 120 | + "Ctrl-.": function(cm) { server.selectName(cm); } | |
| 121 | + }) | |
| 122 | + editor.on("cursorActivity", function(cm) { server.updateArgHints(cm); }); | |
| 123 | + }); | |
| 124 | + | |
| 125 | + var editor = CodeMirror.fromTextArea(document.getElementById("code"), { | |
| 126 | + lineNumbers: true, | |
| 127 | + mode: "javascript" | |
| 128 | + }); | |
| 129 | +</script> | |
| 130 | + | |
| 131 | + </article> | ... | ... |