From 1c266a68b1749dcaedb369af2219e2e55117b7e0 Mon Sep 17 00:00:00 2001 From: Silvan Calarco Date: Fri, 2 Oct 2020 13:05:50 +0200 Subject: [PATCH] codemirror: update to 5.58.1 --- scripts/codemirror/.github/ISSUE_TEMPLATE.md | 5 + .../.github/PULL_REQUEST_TEMPLATE.md | 5 + scripts/codemirror/AUTHORS | 73 ++ scripts/codemirror/CHANGELOG.md | 260 +++++++ scripts/codemirror/addon/comment/comment.js | 4 +- .../addon/comment/continuecomment.js | 74 +- scripts/codemirror/addon/dialog/dialog.js | 4 +- scripts/codemirror/addon/display/panel.js | 54 +- .../codemirror/addon/display/placeholder.js | 16 +- scripts/codemirror/addon/edit/closetag.js | 43 +- scripts/codemirror/addon/edit/continuelist.js | 4 +- .../codemirror/addon/edit/matchbrackets.js | 12 +- scripts/codemirror/addon/fold/foldcode.js | 9 +- scripts/codemirror/addon/fold/foldgutter.js | 33 +- scripts/codemirror/addon/hint/css-hint.js | 12 +- .../codemirror/addon/hint/javascript-hint.js | 7 +- scripts/codemirror/addon/hint/show-hint.js | 39 +- scripts/codemirror/addon/hint/sql-hint.js | 2 +- scripts/codemirror/addon/hint/xml-hint.js | 40 +- scripts/codemirror/addon/lint/lint.css | 24 +- scripts/codemirror/addon/lint/lint.js | 37 +- scripts/codemirror/addon/merge/merge.js | 16 +- scripts/codemirror/addon/mode/loadmode.js | 22 +- .../addon/runmode/runmode-standalone.js | 441 +++++++---- scripts/codemirror/addon/runmode/runmode.js | 14 +- .../codemirror/addon/runmode/runmode.node.js | 396 ++++++---- .../addon/scroll/annotatescrollbar.js | 14 +- .../addon/search/match-highlighter.js | 4 +- .../codemirror/addon/search/searchcursor.js | 35 +- scripts/codemirror/addon/tern/tern.js | 11 +- scripts/codemirror/addon/wrap/hardwrap.js | 30 +- scripts/codemirror/demo/folding.html | 53 +- .../codemirror/demo/runmode-standalone.html | 61 ++ scripts/codemirror/demo/simplemode.html | 3 +- scripts/codemirror/demo/theme.html | 14 +- scripts/codemirror/demo/vim.html | 10 +- scripts/codemirror/doc/manual.html | 180 ++++- scripts/codemirror/doc/realworld.html | 10 +- scripts/codemirror/doc/releases.html | 172 +++++ scripts/codemirror/index.html | 24 +- scripts/codemirror/keymap/emacs.js | 3 +- scripts/codemirror/keymap/sublime.js | 39 +- scripts/codemirror/keymap/vim.js | 333 ++++++-- scripts/codemirror/lib/codemirror.css | 22 +- scripts/codemirror/lib/codemirror.js | 726 +++++++++--------- scripts/codemirror/mode/apl/index.html | 2 +- scripts/codemirror/mode/asciiarmor/index.html | 2 +- scripts/codemirror/mode/asn.1/index.html | 2 +- scripts/codemirror/mode/asterisk/asterisk.js | 28 +- scripts/codemirror/mode/asterisk/index.html | 2 +- scripts/codemirror/mode/brainfuck/index.html | 2 +- scripts/codemirror/mode/clike/clike.js | 85 +- scripts/codemirror/mode/clike/index.html | 2 +- scripts/codemirror/mode/clike/scala.html | 2 +- scripts/codemirror/mode/clojure/index.html | 2 +- scripts/codemirror/mode/cmake/index.html | 2 +- scripts/codemirror/mode/cobol/index.html | 2 +- .../codemirror/mode/coffeescript/index.html | 2 +- scripts/codemirror/mode/commonlisp/index.html | 2 +- scripts/codemirror/mode/crystal/index.html | 2 +- scripts/codemirror/mode/css/css.js | 212 ++--- scripts/codemirror/mode/css/gss.html | 2 +- scripts/codemirror/mode/css/index.html | 2 +- scripts/codemirror/mode/css/less.html | 2 +- scripts/codemirror/mode/css/scss.html | 2 +- scripts/codemirror/mode/cypher/cypher.js | 3 +- scripts/codemirror/mode/cypher/index.html | 2 +- scripts/codemirror/mode/d/index.html | 2 +- scripts/codemirror/mode/dart/dart.js | 13 +- scripts/codemirror/mode/dart/index.html | 2 +- scripts/codemirror/mode/diff/index.html | 2 +- scripts/codemirror/mode/django/index.html | 2 +- scripts/codemirror/mode/dockerfile/index.html | 2 +- scripts/codemirror/mode/dtd/index.html | 2 +- scripts/codemirror/mode/dylan/index.html | 2 +- scripts/codemirror/mode/ebnf/index.html | 2 +- scripts/codemirror/mode/ecl/index.html | 2 +- scripts/codemirror/mode/eiffel/index.html | 2 +- scripts/codemirror/mode/elm/elm.js | 278 ++++--- scripts/codemirror/mode/elm/index.html | 2 +- scripts/codemirror/mode/erlang/index.html | 2 +- scripts/codemirror/mode/factor/index.html | 2 +- scripts/codemirror/mode/fcl/index.html | 2 +- scripts/codemirror/mode/forth/index.html | 2 +- scripts/codemirror/mode/fortran/index.html | 2 +- scripts/codemirror/mode/gas/index.html | 2 +- scripts/codemirror/mode/gfm/index.html | 2 +- scripts/codemirror/mode/gherkin/index.html | 2 +- scripts/codemirror/mode/go/index.html | 2 +- scripts/codemirror/mode/groovy/index.html | 2 +- scripts/codemirror/mode/haml/index.html | 2 +- .../codemirror/mode/handlebars/handlebars.js | 6 +- scripts/codemirror/mode/handlebars/index.html | 4 +- scripts/codemirror/mode/haskell/index.html | 2 +- scripts/codemirror/mode/haxe/index.html | 2 +- .../codemirror/mode/htmlembedded/index.html | 2 +- scripts/codemirror/mode/htmlmixed/index.html | 2 +- scripts/codemirror/mode/http/index.html | 2 +- scripts/codemirror/mode/idl/index.html | 2 +- scripts/codemirror/mode/javascript/index.html | 2 +- .../codemirror/mode/javascript/javascript.js | 25 +- scripts/codemirror/mode/javascript/test.js | 8 + .../mode/javascript/typescript.html | 2 +- scripts/codemirror/mode/jinja2/index.html | 2 +- scripts/codemirror/mode/jsx/index.html | 2 +- scripts/codemirror/mode/julia/index.html | 2 +- scripts/codemirror/mode/julia/julia.js | 30 +- scripts/codemirror/mode/livescript/index.html | 2 +- scripts/codemirror/mode/lua/index.html | 2 +- scripts/codemirror/mode/markdown/index.html | 13 +- scripts/codemirror/mode/markdown/markdown.js | 20 +- scripts/codemirror/mode/markdown/test.js | 16 +- .../codemirror/mode/mathematica/index.html | 2 +- scripts/codemirror/mode/mbox/index.html | 2 +- scripts/codemirror/mode/meta.js | 12 +- scripts/codemirror/mode/mirc/index.html | 2 +- scripts/codemirror/mode/mllike/index.html | 2 +- scripts/codemirror/mode/modelica/index.html | 2 +- scripts/codemirror/mode/mscgen/index.html | 2 +- scripts/codemirror/mode/mumps/index.html | 2 +- scripts/codemirror/mode/nginx/index.html | 2 +- scripts/codemirror/mode/nsis/index.html | 2 +- scripts/codemirror/mode/nsis/nsis.js | 2 +- scripts/codemirror/mode/ntriples/index.html | 2 +- scripts/codemirror/mode/octave/index.html | 2 +- scripts/codemirror/mode/octave/octave.js | 2 +- scripts/codemirror/mode/oz/index.html | 2 +- scripts/codemirror/mode/pascal/index.html | 2 +- scripts/codemirror/mode/pascal/pascal.js | 17 +- scripts/codemirror/mode/pegjs/index.html | 2 +- scripts/codemirror/mode/perl/index.html | 2 +- scripts/codemirror/mode/php/index.html | 2 +- scripts/codemirror/mode/pig/index.html | 2 +- scripts/codemirror/mode/powershell/index.html | 6 +- .../codemirror/mode/powershell/powershell.js | 2 +- scripts/codemirror/mode/powershell/test.js | 2 +- scripts/codemirror/mode/properties/index.html | 2 +- scripts/codemirror/mode/protobuf/index.html | 2 +- scripts/codemirror/mode/protobuf/protobuf.js | 5 +- scripts/codemirror/mode/pug/index.html | 2 +- scripts/codemirror/mode/pug/pug.js | 16 +- scripts/codemirror/mode/puppet/index.html | 2 +- scripts/codemirror/mode/python/index.html | 2 +- scripts/codemirror/mode/python/python.js | 10 +- scripts/codemirror/mode/q/index.html | 2 +- scripts/codemirror/mode/r/index.html | 2 +- scripts/codemirror/mode/rpm/index.html | 2 +- scripts/codemirror/mode/rst/index.html | 2 +- scripts/codemirror/mode/ruby/index.html | 2 +- scripts/codemirror/mode/ruby/ruby.js | 41 +- scripts/codemirror/mode/rust/index.html | 10 +- scripts/codemirror/mode/rust/rust.js | 4 +- scripts/codemirror/mode/sas/index.html | 2 +- scripts/codemirror/mode/sas/sas.js | 2 +- scripts/codemirror/mode/sass/index.html | 2 +- scripts/codemirror/mode/scheme/index.html | 2 +- scripts/codemirror/mode/shell/index.html | 2 +- scripts/codemirror/mode/sieve/index.html | 2 +- scripts/codemirror/mode/slim/index.html | 2 +- scripts/codemirror/mode/smalltalk/index.html | 2 +- scripts/codemirror/mode/smarty/index.html | 2 +- scripts/codemirror/mode/solr/index.html | 2 +- scripts/codemirror/mode/soy/index.html | 2 +- scripts/codemirror/mode/soy/soy.js | 237 +++++- scripts/codemirror/mode/soy/test.js | 92 ++- scripts/codemirror/mode/sparql/index.html | 2 +- .../codemirror/mode/spreadsheet/index.html | 2 +- scripts/codemirror/mode/sql/index.html | 2 +- scripts/codemirror/mode/sql/sql.js | 17 +- scripts/codemirror/mode/stex/index.html | 2 +- scripts/codemirror/mode/stex/stex.js | 2 +- scripts/codemirror/mode/stylus/index.html | 2 +- scripts/codemirror/mode/stylus/stylus.js | 2 +- scripts/codemirror/mode/swift/index.html | 2 +- scripts/codemirror/mode/tcl/index.html | 2 +- scripts/codemirror/mode/tcl/tcl.js | 3 +- scripts/codemirror/mode/textile/index.html | 2 +- scripts/codemirror/mode/tiddlywiki/index.html | 2 +- scripts/codemirror/mode/tiki/index.html | 2 +- scripts/codemirror/mode/toml/index.html | 2 +- scripts/codemirror/mode/tornado/index.html | 2 +- scripts/codemirror/mode/troff/index.html | 2 +- scripts/codemirror/mode/ttcn-cfg/index.html | 2 +- scripts/codemirror/mode/ttcn/index.html | 2 +- scripts/codemirror/mode/turtle/index.html | 2 +- scripts/codemirror/mode/twig/index.html | 6 +- scripts/codemirror/mode/vb/index.html | 2 +- scripts/codemirror/mode/vbscript/index.html | 2 +- scripts/codemirror/mode/velocity/index.html | 2 +- scripts/codemirror/mode/verilog/index.html | 2 +- scripts/codemirror/mode/verilog/verilog.js | 3 +- scripts/codemirror/mode/vhdl/index.html | 2 +- scripts/codemirror/mode/vue/index.html | 2 +- scripts/codemirror/mode/wast/index.html | 73 ++ scripts/codemirror/mode/wast/test.js | 321 ++++++++ scripts/codemirror/mode/wast/wast.js | 41 + scripts/codemirror/mode/xml/index.html | 2 +- scripts/codemirror/mode/xml/xml.js | 11 + scripts/codemirror/mode/xquery/index.html | 2 +- scripts/codemirror/mode/yacas/index.html | 2 +- .../mode/yaml-frontmatter/index.html | 2 +- .../mode/yaml-frontmatter/yaml-frontmatter.js | 2 +- scripts/codemirror/mode/yaml/index.html | 2 +- scripts/codemirror/mode/z80/index.html | 2 +- scripts/codemirror/package.json | 14 +- scripts/codemirror/rollup.config.js | 42 +- .../addon/runmode/codemirror-standalone.js | 22 + .../src/addon/runmode/codemirror.node.js | 21 + .../src/addon/runmode/runmode-standalone.js | 2 + .../src/addon/runmode/runmode.node.js | 2 + scripts/codemirror/src/display/scrolling.js | 4 +- scripts/codemirror/src/display/selection.js | 7 +- .../codemirror/src/display/update_display.js | 5 +- scripts/codemirror/src/display/update_line.js | 8 +- scripts/codemirror/src/edit/CodeMirror.js | 9 +- scripts/codemirror/src/edit/commands.js | 4 +- scripts/codemirror/src/edit/drop_events.js | 41 +- scripts/codemirror/src/edit/fromTextArea.js | 2 +- scripts/codemirror/src/edit/key_events.js | 6 +- scripts/codemirror/src/edit/main.js | 2 +- scripts/codemirror/src/edit/methods.js | 32 +- scripts/codemirror/src/edit/mouse_events.js | 6 +- scripts/codemirror/src/edit/options.js | 8 +- .../src/input/ContentEditableInput.js | 25 +- scripts/codemirror/src/input/TextareaInput.js | 10 + scripts/codemirror/src/input/input.js | 2 +- scripts/codemirror/src/input/keymap.js | 2 +- scripts/codemirror/src/input/keynames.js | 2 +- scripts/codemirror/src/input/movement.js | 1 + scripts/codemirror/src/line/highlight.js | 2 +- scripts/codemirror/src/line/line_data.js | 2 +- .../src/measurement/position_measurement.js | 18 +- scripts/codemirror/src/model/Doc.js | 5 +- scripts/codemirror/src/model/changes.js | 5 +- scripts/codemirror/src/util/bidi.js | 5 +- scripts/codemirror/src/util/misc.js | 26 +- scripts/codemirror/test/annotatescrollbar.js | 55 ++ scripts/codemirror/test/driver.js | 13 +- scripts/codemirror/test/index.html | 29 +- scripts/codemirror/test/lint.js | 2 +- scripts/codemirror/test/phantom_driver.js | 31 - scripts/codemirror/test/run.js | 40 +- scripts/codemirror/test/search_test.js | 8 +- scripts/codemirror/test/sublime_test.js | 19 +- scripts/codemirror/test/test.js | 48 +- scripts/codemirror/test/vim_test.js | 374 ++++++++- scripts/codemirror/theme/ayu-dark.css | 42 + scripts/codemirror/theme/ayu-mirage.css | 43 ++ scripts/codemirror/theme/darcula.css | 24 +- scripts/codemirror/theme/material-darker.css | 135 ++++ scripts/codemirror/theme/material-ocean.css | 135 ++++ .../codemirror/theme/material-palenight.css | 135 ++++ scripts/codemirror/theme/material.css | 154 +++- scripts/codemirror/theme/moxer.css | 143 ++++ scripts/codemirror/theme/yonce.css | 4 +- scripts/codemirror/theme/zenburn.css | 2 +- 256 files changed, 5417 insertions(+), 1669 deletions(-) create mode 100644 scripts/codemirror/.github/ISSUE_TEMPLATE.md create mode 100644 scripts/codemirror/.github/PULL_REQUEST_TEMPLATE.md create mode 100644 scripts/codemirror/demo/runmode-standalone.html create mode 100644 scripts/codemirror/mode/wast/index.html create mode 100644 scripts/codemirror/mode/wast/test.js create mode 100644 scripts/codemirror/mode/wast/wast.js create mode 100644 scripts/codemirror/src/addon/runmode/codemirror-standalone.js create mode 100644 scripts/codemirror/src/addon/runmode/codemirror.node.js create mode 100644 scripts/codemirror/src/addon/runmode/runmode-standalone.js create mode 100644 scripts/codemirror/src/addon/runmode/runmode.node.js create mode 100644 scripts/codemirror/test/annotatescrollbar.js delete mode 100644 scripts/codemirror/test/phantom_driver.js create mode 100644 scripts/codemirror/theme/ayu-dark.css create mode 100644 scripts/codemirror/theme/ayu-mirage.css create mode 100644 scripts/codemirror/theme/material-darker.css create mode 100644 scripts/codemirror/theme/material-ocean.css create mode 100644 scripts/codemirror/theme/material-palenight.css create mode 100644 scripts/codemirror/theme/moxer.css diff --git a/scripts/codemirror/.github/ISSUE_TEMPLATE.md b/scripts/codemirror/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..49e2dcb --- /dev/null +++ b/scripts/codemirror/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/scripts/codemirror/.github/PULL_REQUEST_TEMPLATE.md b/scripts/codemirror/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..ea7cbc7 --- /dev/null +++ b/scripts/codemirror/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,5 @@ + diff --git a/scripts/codemirror/AUTHORS b/scripts/codemirror/AUTHORS index ab98a58..bb017e9 100644 --- a/scripts/codemirror/AUTHORS +++ b/scripts/codemirror/AUTHORS @@ -15,11 +15,13 @@ Adán Lobato Aditya Toshniwal Adrian Aichner Adrian Heine +Adrian Kunz Adrien Bertrand aeroson Ahmad Amireh Ahmad M. Zawawi ahoward +Ajin Abraham Akeksandr Motsjonov Alasdair Smith AlbertHilb @@ -31,6 +33,7 @@ Alexander Schepanovski Alexander Shvets Alexander Solovyov Alexandre Bique +Alex Churchill alexey-k Alex Piggott Aliaksei Chapyzhenka @@ -72,11 +75,13 @@ anthonygego Anthony Gégo Anthony Grimes Anton Kovalyov +antosarho Apollo Zhu AQNOUCH Mohammed Aram Shatakhtsyan areos Arnab Bose +Arnoud Buzing Arsène von Wyss Arthur Müller Arun Narasani @@ -95,6 +100,9 @@ Bastian Müller belhaj Bem Jones-Bey benbro +Benedikt Meurer +benhormann +Ben Hormann Beni Cherniavsky-Paskin Benjamin DeCoste Benjamin Young @@ -106,6 +114,7 @@ Bert Chang Bharad BigBlueHat Billy Moon +Bin Ni binny Bjorn Hansen B Krishna Chaitanya @@ -115,12 +124,14 @@ Bo boomyjee Bo Peng borawjm +Boris K Brad Metcalf Brandon Frohs Brandon Wamboldt Bret Little Brett Zamir Brian Grinstead +BrianHung Brian Sletten brrd Bruce Mitchener @@ -132,6 +143,7 @@ Calin Barbat callodacity Camilo Roca Casey Klebba +cBiscuit87 César González Íñiguez Chad Jolly Chandra Sekhar Pydi @@ -158,6 +170,7 @@ Christopher Pfohl Christopher Wallis Chunliang Lyu ciaranj +clone-it clso CodeAnimal CodeBitt @@ -167,6 +180,7 @@ ComFreek Cristian Prieto Curran Kelleher Curtis Gagliardi +d8888 dagsta daines Dale Jung @@ -194,6 +208,7 @@ David Barnett David H. Bronke David Mignot David Pathakjee +David Rodrigues David Santana David Vázquez David Whittington @@ -206,6 +221,7 @@ Dick Choi Diego Fernandez dignifiedquire Dimage Sapelkin +Dinindu D. Wanniarachchi dmaclach Dmitry Kiselyov domagoj412 @@ -221,10 +237,13 @@ Dror BG Duncan Lilley duralog dwelle +Ealton eborden +edoroshenko edsharp ekhaled Elisée +elpnt Emmanuel Schanzer Enam Mijbah Noor Eric Allam @@ -249,11 +268,13 @@ Filype Pereira finalfantasia flack Florian Felten +Fons van der Plas Forbes Lindesay ForbesLindesay Ford_Lawnmower Forrest Oliphant Franco Catena +Frank Seifferth Frank Wiegand fraxx001 Fredrik Borg @@ -284,20 +305,25 @@ Grant Skinner greengiant Gregory Koberger Grzegorz Mazur +Guang Li Guan Gui Guillaume Massé Guillaume Massé guraga Gustavo Rodrigues Hakan Tunc +Hanno Fellmann Hans Engel Hanzhao Deng +Haoran Yu Harald Schilly Hardest Harshvardhan Gupta +Hasan Delibaş Hasan Karahan Heanes Hector Oswaldo Caballero +Hein Htat Hélio Hendrik Wallbaum Henrik Haugbølle @@ -306,22 +332,29 @@ hidaiy Hiroyuki Makino hitsthings Hocdoc +Howard +Howard Jing Hugues Malphettes Ian Beck Ian Davies Ian Dickinson +ianhi Ian Rose Ian Wehrman Ian Wetherbee Ice White ICHIKAWA, Yuji idleberg +Igor Petruk ilvalle Ilya Kharlamov +Ilya Zverev Ingo Richter +Intervue Irakli Gozalishvili Ivan Kurnosov Ivoah +Jack Douglas Jacob Lee Jaimin Jake Peyser @@ -329,6 +362,7 @@ Jakob Miland Jakub Vrana Jakub Vrána James Campos +James Cockshull James Howard James Thorne Jamie Hill @@ -351,6 +385,7 @@ Jason Johnston Jason San Jose Jason Siefken Jayaprabhakar +Jay Contonio Jaydeep Solanki Jean Boussier Jeff Blaisdell @@ -370,10 +405,13 @@ Joel Einbinder joelpinheiro joewalsh Johan Ask +Johannes +John Chen John Connor John-David Dalton John Engler John Lees-Miller +John Ryan John Snelson John Van Der Loo Jon Ander Peñalba @@ -386,6 +424,7 @@ Jon Gacnik jongalloway Jon Malmaud Jon Sangster +Joo Joost-Wim Boekesteijn Joseph Pecoraro Josh Barnes @@ -408,6 +447,7 @@ jwallers@gmail.com kaniga karevn Karol +Kaushik Kulkarni Kayur Patel Kazuhito Hokamura kcwiakala @@ -430,6 +470,7 @@ koops Kris Ciccarello ks-ifware kubelsmieci +kvncp KwanEsq Kyle Kelley KyleMcNutt @@ -438,6 +479,7 @@ Lanfei Lanny laobubu Laszlo Vidacs +leaf leaf corcoran Lemmon Leo Baschy @@ -451,10 +493,12 @@ Lior Shub LloydMilligan LM lochel +Lonnie Abelbeck Lorenzo Simionato Lorenzo Stoakes Louis Mauchet Luca Fabbri +Lucas Buchala Luciano Longo Luciano Santana Lu Fangjian @@ -481,6 +525,7 @@ Mário Gonçalves Mario Pietsch Mark Anderson Mark Dalgleish +Mark Hamstra Mark Lentczner Marko Bonaci Mark Peace @@ -499,11 +544,13 @@ mats cronqvist Matt Gaide Matthew Bauer Matthew Beale +Matthew Casperson matthewhayes Matthew Rathbone Matthew Suozzo Matthias Bussonnier Matthias BUSSONNIER +Mattia Astorino Matt MacPherson Matt McDonald Matt Pass @@ -518,6 +565,7 @@ Max Xiantu mbarkhau McBrainy mce2 +Mélanie Chauvel melpon meshuamam Metatheos @@ -585,15 +633,21 @@ Nikita Vasilyev Nikolaj Kappler Nikolay Kostov nilp0inter +Nils Knappmeier Nisarg Jhaveri nlwillia noragrossman Norman Rzepka Nouzbe Oleksandr Yakovenko +Olivia Ytterbrink +Opender Singh opl- Oreoluwa Onatemowo +orionlee +oscar.lofwenhamn Oskar Segersvärd +ossdev overdodactyl pablo pabloferz @@ -606,11 +660,13 @@ paris Paris Paris Kasidiaris Patil Arpith +Patrick Kettner Patrick Stoica Patrick Strawderman Paul Garvin Paul Ivanov Paul Masson +Paul Schmidt Pavel Pavel Feldman Pavel Petržela @@ -621,6 +677,7 @@ peter Peter Flynn peterkroon Peter Kroon +Peter László Philipp A Philipp Markovics Philip Stadermann @@ -631,6 +688,7 @@ Pontus Melke prasanthj Prasanth J Prayag Verma +prendota Prendota Qiang Li Radek Piórkowski @@ -644,6 +702,7 @@ Randy Luecke Raphael Amorim Rasmus Erik Voel Jensen Rasmus Schultz +raymondf Raymond Hill ray ratchup Ray Ratchup @@ -659,10 +718,14 @@ Robert Crossfield Robert Martin Roberto Abdelkader Martínez Pérez robertop23 +Roberto Vidal Robert Plummer +Roman Janusz Rrandom Rrrandom Ruslan Osmanov +rvalavicius +Ryan Pangrle Ryan Petrello Ryan Prior ryu-sato @@ -705,6 +768,7 @@ Shiv Deepak Shmuel Englard Shubham Jain Siamak Mokhtari +Siddhartha Gunti silverwind Simon Edwards sinkuu @@ -738,7 +802,9 @@ Tako Schotanus Takuji Shimokawa Takuya Matsuyama Tarmil +T. Brandon Ashley TDaglis +Teja tel Tentone tfjgeorge @@ -754,13 +820,16 @@ thomasmaclean Thomas Schmid Tim Alby Tim Baumann +Tim Gates Timothy Farrell Timothy Gu Timothy Hatcher +Tim van der Lippe Tobias Bertelsen TobiasBg Todd Berman Todd Kennedy +tokafew420 Tomas-A Tomas Varaneckas Tom Erik Støwer @@ -778,9 +847,11 @@ TSUYUSATO Kitsune Tugrul Elmas twifkak Tyler Long +Tyler Makaro Vadim Dyachenko Vadzim Ramanenka Vaibhav Sagar +vamshi.revu VapidWorx Vestimir Markov vf @@ -813,8 +884,10 @@ Yuvi Panda Yvonnick Esnault Zac Anger Zachary Dremann +ZeeshanNoor Zeno Rocha Zhang Hao Ziv +zoobestik zziuni 魏鹏刚 diff --git a/scripts/codemirror/CHANGELOG.md b/scripts/codemirror/CHANGELOG.md index 061c721..d3e3fe4 100644 --- a/scripts/codemirror/CHANGELOG.md +++ b/scripts/codemirror/CHANGELOG.md @@ -1,3 +1,263 @@ +## 5.58.1 (2020-09-23) + +### Bug fixes + +[placeholder addon](https://codemirror.net/doc/manual.html#addon_placeholder): Remove arrow function that ended up in the code. + +## 5.58.0 (2020-09-21) + +### Bug fixes + +Make backspace delete by code point, not glyph. + +Suppress flickering focus outline when clicking on scrollbars in Chrome. + +Fix a bug that prevented attributes added via `markText` from showing up unless the span also had some other styling. + +Suppress cut and paste context menu entries in readonly editors in Chrome. + +[placeholder addon](https://codemirror.net/doc/manual.html#addon_placeholder): Update placeholder visibility during composition. + +### New features + +Make it less cumbersome to style new lint message types. + +[vim bindings](https://codemirror.net/demo/vim.html): Support black hole register, `gn` and `gN` + +## 5.57.0 (2020-08-20) + +### Bug fixes + +Fix issue that broke binding the macOS Command key. + +[comment addon](https://codemirror.net/doc/manual.html#addon_comment): Keep selection in front of inserted markers when adding a block comment. + +[css mode](https://codemirror.net/mode/css/): Recognize more properties and value names. + +[annotatescrollbar addon](https://codemirror.net/doc/manual.html#addon_annotatescrollbar): Don't hide matches in collapsed content. + +### New features + +[vim bindings](https://codemirror.net/demo/vim.html): Support tag text objects in xml and html modes. + +## 5.56.0 (2020-07-20) + +### Bug fixes + +Line-wise pasting was fixed on Chrome Windows. + +[wast mode](https://codemirror.net/mode/wast/): Follow standard changes. + +[soy mode](https://codemirror.net/mode/soy/): Support import expressions, template type, and loop indices. + +[sql-hint addon](https://codemirror.net/doc/manual.html#addon_sql-hint): Improve handling of double quotes. + +### New features + +[show-hint addon](https://codemirror.net/doc/manual.html#addon_show-hint): New option `scrollMargin` to control how many options are visible beyond the selected one. + +[hardwrap addon](https://codemirror.net/doc/manual.html#addon_hardwrap): New option `forceBreak` to disable breaking of words that are longer than a line. + +## 5.55.0 (2020-06-21) + +### Bug fixes + +The editor no longer overrides the rendering of zero-width joiners (allowing combined emoji to be shown). + +[vim bindings](https://codemirror.net/demo/vim.html): Fix an issue where the `vim-mode-change` event was fired twice. + +[javascript mode](https://codemirror.net/mode/javascript/): Only allow `-->`-style comments at the start of a line. + +[julia mode](https://codemirror.net/mode/julia/): Improve indentation. + +[pascal mode](https://codemirror.net/mode/pascal/index.html): Recognize curly bracket comments. + +[runmode addon](https://codemirror.net/doc/manual.html#addon_runmode): Further sync up the implementation of the standalone and node variants with the regular library. + +### New features + +[loadmode addon](https://codemirror.net/doc/manual.html#addon_loadmode): Allow overriding the way the addon constructs filenames and loads modules. + +## 5.54.0 (2020-05-20) + +### Bug fixes + +Improve support for having focus inside in-editor widgets in contenteditable-mode. + +Fix issue where the scroll position could jump when clicking on a selection in Chrome. + +[python mode](https://codemirror.net/mode/python/): Better format string support. + +[javascript mode](https://codemirror.net/mode/javascript/): Improve parsing of private properties and class fields. + +[matchbrackets addon](https://codemirror.net/doc/manual.html#addon_matchbrackets): Disable highlighting when the editor doesn't have focus. + +### New features + +[runmode addon](https://codemirror.net/doc/manual.html#addon_runmode): Properly support for cross-line lookahead. + +[vim bindings](https://codemirror.net/demo/vim.html): Allow Ex-Commands with non-word names. + +[gfm mode](https://codemirror.net/mode/gfm/): Add a `fencedCodeBlockDefaultMode` option. + +## 5.53.2 (2020-04-21) + +### Bug fixes + +[show-hint addon](https://codemirror.net/doc/manual.html#addon_show-hint): Fix a regression that broke completion picking. + +## 5.53.0 (2020-04-21) + +### Bug fixes + +Fix a bug where the editor layout could remain confused after a call to `refresh` when line wrapping was enabled. + +[dialog addon](https://codemirror.net/doc/manual.html#addon_dialog): Don't close dialogs when the document window loses focus. + +[merge addon](https://codemirror.net/doc/manual.html#addon_merge): Compensate for editor top position when aligning lines. + +[vim bindings](https://codemirror.net/demo/vim.html): Improve EOL handling. + +[emacs bindings](https://codemirror.net/demo/emacs.html): Include default keymap as a fallback. + +[julia mode](https://codemirror.net/mode/julia/): Fix an infinite loop bug. + +[show-hint addon](https://codemirror.net/doc/manual.html#addon_show-hint): Scroll cursor into view when picking a completion. + +### New features + +New option: [`screenReaderLabel`](https://codemirror.net/doc/manual.html#option_screenReaderLabel) to add a label to the editor. + +New mode: [wast](https://codemirror.net/mode/wast/). + +## 5.52.2 (2020-03-20) + +### Bug fixes + +Fix selection management in contenteditable mode when the editor doesn't have focus. + +Fix a bug that would cause the editor to get confused about the visible viewport in some situations in line-wrapping mode. + +[markdown mode](https://codemirror.net/mode/markdown/): Don't treat single dashes as setext header markers. + +[zenburn theme](https://codemirror.net/demo/theme.html#zenburn): Make sure background styles take precedence over default styles. + +[css mode](https://codemirror.net/mode/css/): Recognize a number of new properties. + +## 5.52.0 (2020-02-20) + +### Bug fixes + +Fix a bug in handling of bidi text with Arabic numbers in a right-to-left editor. + +Fix a crash when combining file drop with a `"beforeChange"` filter. + +Prevent issue when passing negative coordinates to `scrollTo`. + +### New features + +[lint](https://codemirror.net/doc/manual.html#addon_lint) and [tern](https://codemirror.net/demo/tern.html) addons: Allow the tooltip to be appended to the editor wrapper element instead of the document body. + +## 5.51.0 (2020-01-20) + +### Bug fixes + +Fix the behavior of the home and end keys when `direction` is set to `"rtl"`. + +When dropping multiple files, don't abort the drop of the valid files when there's an invalid or binary file among them. + +Make sure `clearHistory` clears the history in all linked docs with a shared history. + +[vim bindings](https://codemirror.net/demo/vim.html): Fix behavior of `'` and `` ` `` marks, fix `R` in visual mode. + +### New features + +[vim bindings](https://codemirror.net/demo/vim.html): Support `gi`, `gI`, and `gJ`. + +## 5.50.2 (2020-01-01) + +### Bug fixes + +Fix bug that broke removal of line widgets. + +## 5.50.0 (2019-12-20) + +### Bug fixes + +Make Shift-Delete to cut work on Firefox. + +[closetag addon](https://codemirror.net/demo/closetag.html): Properly handle self-closing tags. + +[handlebars mode](https://codemirror.net/mode/handlebars/): Fix triple-brace support. + +[searchcursor addon](https://codemirror.net/doc/manual.html#addon_searchcursor): Support mathing `$` in reverse regexp search. + +[panel addon](https://codemirror.net/doc/manual.html#addon_panel): Don't get confused by changing panel sizes. + +[javascript-hint addon](https://codemirror.net/doc/manual.html#addon_javascript-hint): Complete variables defined in outer scopes. + +[sublime bindings](https://codemirror.net/demo/sublime.html): Make by-subword motion more consistent with Sublime Text. + +[julia mode](https://codemirror.net/mode/julia/): Don't break on zero-prefixed integers. + +[elm mode](https://codemirror.net/mode/elm/): Sync with upstream version. + +[sql mode](https://codemirror.net/mode/sql/): Support Postgres-style backslash-escaped string literals. + +### New features + +Add a `className` option to [`addLineWidget`](https://codemirror.net/doc/manual.html#addLineWidget). + +[foldcode addon](https://codemirror.net/doc/manual.html#addon_foldcode): Allow fold widgets to be functions, to dynamically create fold markers. + +New themes: [ayu-dark](https://codemirror.net/demo/theme.html#ayu-dark) and [ayu-mirage](https://codemirror.net/demo/theme.html#ayu-mirage). + +## 5.49.2 (2019-10-21) + +### Bug fixes + +[sublime bindings](https://codemirror.net/demo/sublime.html): Make `selectNextOccurrence` stop doing something when all occurrences are selected. + +[continuecomment addon](https://codemirror.net/doc/manual.html#addon_continuecomment): Respect `indentWithTabs` option. + +[foldgutter addon](https://codemirror.net/doc/manual.html#addon_foldgutter): Optimize by reusing DOM when possible. + +[markdown mode](https://codemirror.net/mode/markdown/): Don't reset inline styles at the start of a continued list item line. + +[clike mode](https://codemirror.net/mode/clike/): Add a configuration for Objective-C++. + +## 5.49.0 (2019-09-20) + +### Bug fixes + +[octave mode](https://codemirror.net/mode/octave/index.html): Don't mark common punctuation as error. + +[clike mode](https://codemirror.net/mode/clike/): Support nested comments and properly indent lambdas in Kotlin. + +[foldgutter](https://codemirror.net/doc/manual.html#addon_foldgutter) and [annotatescrollbar](https://codemirror.net/doc/manual.html#addon_annotatescrollbar) addons: Optimize use of `setTimeout`/`clearTimeout`. + +### New features + +New themes: [moxer](https://codemirror.net/demo/theme.html#moxer), [material-darker](https://codemirror.net/demo/theme.html#material-darker), [material-palenight](https://codemirror.net/demo/theme.html#material-palenight), [material-ocean](https://codemirror.net/demo/theme.html#material-ocean). + +[xml mode](https://codemirror.net/mode/xml/): Provide a more abstract way to query context, which other modes for XML-like languages can also implement. + +## 5.48.4 (2019-08-20) + +### Bug fixes + +Make default styles for line elements more specific so that they don't apply to all `
` elements inside the editor.
+
+Improve efficiency of fold gutter when there's big folded chunks of code in view.
+
+Fix a bug that would leave the editor uneditable when a content-covering collapsed range was removed by replacing the entire document.
+
+[julia mode](https://codemirror.net/mode/julia/): Support number separators.
+
+[asterisk mode](https://codemirror.net/mode/asterisk/): Improve comment support.
+
+[handlebars mode](https://codemirror.net/mode/handlebars/): Support triple-brace tags.
+
 ## 5.48.2 (2019-07-20)
 
 ### Bug fixes
diff --git a/scripts/codemirror/addon/comment/comment.js b/scripts/codemirror/addon/comment/comment.js
index 8394e85..dac48d0 100644
--- a/scripts/codemirror/addon/comment/comment.js
+++ b/scripts/codemirror/addon/comment/comment.js
@@ -13,7 +13,7 @@
 
   var noOptions = {};
   var nonWS = /[^\s\u00a0]/;
-  var Pos = CodeMirror.Pos;
+  var Pos = CodeMirror.Pos, cmp = CodeMirror.cmpPos;
 
   function firstNonWS(str) {
     var found = str.search(nonWS);
@@ -126,7 +126,9 @@
           if (i != end || lastLineHasText)
             self.replaceRange(lead + pad, Pos(i, 0));
       } else {
+        var atCursor = cmp(self.getCursor("to"), to) == 0, empty = !self.somethingSelected()
         self.replaceRange(endString, to);
+        if (atCursor) self.setSelection(empty ? to : self.getCursor("from"), to)
         self.replaceRange(startString, from);
       }
     });
diff --git a/scripts/codemirror/addon/comment/continuecomment.js b/scripts/codemirror/addon/comment/continuecomment.js
index a5f957b..7ca1b4a 100644
--- a/scripts/codemirror/addon/comment/continuecomment.js
+++ b/scripts/codemirror/addon/comment/continuecomment.js
@@ -9,6 +9,8 @@
   else // Plain browser env
     mod(CodeMirror);
 })(function(CodeMirror) {
+  var nonspace = /\S/g;
+  var repeat = String.prototype.repeat || function (n) { return Array(n + 1).join(this); };
   function continueComment(cm) {
     if (cm.getOption("disableInput")) return CodeMirror.Pass;
     var ranges = cm.listSelections(), mode, inserts = [];
@@ -19,29 +21,57 @@
       if (!mode) mode = modeHere;
       else if (mode != modeHere) return CodeMirror.Pass;
 
-      var insert = null;
-      if (mode.blockCommentStart && mode.blockCommentContinue) {
-        var line = cm.getLine(pos.line).slice(0, pos.ch)
-        var end = line.lastIndexOf(mode.blockCommentEnd), found
-        if (end != -1 && end == pos.ch - mode.blockCommentEnd.length) {
-          // Comment ended, don't continue it
-        } else if ((found = line.lastIndexOf(mode.blockCommentStart)) > -1 && found > end) {
-          insert = line.slice(0, found)
-          if (/\S/.test(insert)) {
-            insert = ""
-            for (var j = 0; j < found; ++j) insert += " "
+      var insert = null, line, found;
+      var blockStart = mode.blockCommentStart, lineCmt = mode.lineComment;
+      if (blockStart && mode.blockCommentContinue) {
+        line = cm.getLine(pos.line);
+        var end = line.lastIndexOf(mode.blockCommentEnd, pos.ch - mode.blockCommentEnd.length);
+        // 1. if this block comment ended
+        // 2. if this is actually inside a line comment
+        if (end != -1 && end == pos.ch - mode.blockCommentEnd.length ||
+            lineCmt && (found = line.lastIndexOf(lineCmt, pos.ch - 1)) > -1 &&
+            /\bcomment\b/.test(cm.getTokenTypeAt({line: pos.line, ch: found + 1}))) {
+          // ...then don't continue it
+        } else if (pos.ch >= blockStart.length &&
+                   (found = line.lastIndexOf(blockStart, pos.ch - blockStart.length)) > -1 &&
+                   found > end) {
+          // reuse the existing leading spaces/tabs/mixed
+          // or build the correct indent using CM's tab/indent options
+          if (nonspaceAfter(0, line) >= found) {
+            insert = line.slice(0, found);
+          } else {
+            var tabSize = cm.options.tabSize, numTabs;
+            found = CodeMirror.countColumn(line, found, tabSize);
+            insert = !cm.options.indentWithTabs ? repeat.call(" ", found) :
+              repeat.call("\t", (numTabs = Math.floor(found / tabSize))) +
+              repeat.call(" ", found - tabSize * numTabs);
           }
-        } else if ((found = line.indexOf(mode.blockCommentContinue)) > -1 && !/\S/.test(line.slice(0, found))) {
-          insert = line.slice(0, found)
+        } else if ((found = line.indexOf(mode.blockCommentContinue)) > -1 &&
+                   found <= pos.ch &&
+                   found <= nonspaceAfter(0, line)) {
+          insert = line.slice(0, found);
         }
         if (insert != null) insert += mode.blockCommentContinue
       }
-      if (insert == null && mode.lineComment && continueLineCommentEnabled(cm)) {
-        var line = cm.getLine(pos.line), found = line.indexOf(mode.lineComment);
-        if (found > -1) {
-          insert = line.slice(0, found);
-          if (/\S/.test(insert)) insert = null;
-          else insert += mode.lineComment + line.slice(found + mode.lineComment.length).match(/^\s*/)[0];
+      if (insert == null && lineCmt && continueLineCommentEnabled(cm)) {
+        if (line == null) line = cm.getLine(pos.line);
+        found = line.indexOf(lineCmt);
+        // cursor at pos 0, line comment also at pos 0 => shift it down, don't continue
+        if (!pos.ch && !found) insert = "";
+        // continue only if the line starts with an optional space + line comment
+        else if (found > -1 && nonspaceAfter(0, line) >= found) {
+          // don't continue if there's only space(s) after cursor or the end of the line
+          insert = nonspaceAfter(pos.ch, line) > -1;
+          // but always continue if the next line starts with a line comment too
+          if (!insert) {
+            var next = cm.getLine(pos.line + 1) || '',
+                nextFound = next.indexOf(lineCmt);
+            insert = nextFound > -1 && nonspaceAfter(0, next) >= nextFound || null;
+          }
+          if (insert) {
+            insert = line.slice(0, found) + lineCmt +
+                     line.slice(found + lineCmt.length).match(/^\s*/)[0];
+          }
         }
       }
       if (insert == null) return CodeMirror.Pass;
@@ -54,6 +84,12 @@
     });
   }
 
+  function nonspaceAfter(ch, str) {
+    nonspace.lastIndex = ch;
+    var m = nonspace.exec(str);
+    return m ? m.index : -1;
+  }
+
   function continueLineCommentEnabled(cm) {
     var opt = cm.getOption("continueComments");
     if (opt && typeof opt == "object")
diff --git a/scripts/codemirror/addon/dialog/dialog.js b/scripts/codemirror/addon/dialog/dialog.js
index 23b06a8..5f1f4aa 100644
--- a/scripts/codemirror/addon/dialog/dialog.js
+++ b/scripts/codemirror/addon/dialog/dialog.js
@@ -82,7 +82,9 @@
         if (e.keyCode == 13) callback(inp.value, e);
       });
 
-      if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close);
+      if (options.closeOnBlur !== false) CodeMirror.on(dialog, "focusout", function (evt) {
+        if (evt.relatedTarget !== null) close();
+      });
     } else if (button = dialog.getElementsByTagName("button")[0]) {
       CodeMirror.on(button, "click", function() {
         close();
diff --git a/scripts/codemirror/addon/display/panel.js b/scripts/codemirror/addon/display/panel.js
index 5faf1d5..4c9f2c0 100644
--- a/scripts/codemirror/addon/display/panel.js
+++ b/scripts/codemirror/addon/display/panel.js
@@ -1,15 +1,15 @@
 // CodeMirror, copyright (c) by Marijn Haverbeke and others
 // Distributed under an MIT license: https://codemirror.net/LICENSE
 
-(function(mod) {
+(function (mod) {
   if (typeof exports == "object" && typeof module == "object") // CommonJS
     mod(require("../../lib/codemirror"));
   else if (typeof define == "function" && define.amd) // AMD
     define(["../../lib/codemirror"], mod);
   else // Plain browser env
     mod(CodeMirror);
-})(function(CodeMirror) {
-  CodeMirror.defineExtension("addPanel", function(node, options) {
+})(function (CodeMirror) {
+  CodeMirror.defineExtension("addPanel", function (node, options) {
     options = options || {};
 
     if (!this.state.panels) initPanels(this);
@@ -25,8 +25,7 @@
       wrapper.insertBefore(node, options.before.node);
     } else if (replace) {
       wrapper.insertBefore(node, options.replace.node);
-      info.panels++;
-      options.replace.clear();
+      options.replace.clear(true);
     } else if (options.position == "bottom") {
       wrapper.appendChild(node);
     } else if (options.position == "before-bottom") {
@@ -38,14 +37,15 @@
     }
 
     var height = (options && options.height) || node.offsetHeight;
-    this._setSize(null, info.heightLeft -= height);
-    if (!replace) {
-      info.panels++;
-    }
-    if (options.stable && isAtTop(this, node))
-      this.scrollTo(null, this.getScrollInfo().top + height)
 
-    return new Panel(this, node, options, height);
+    var panel = new Panel(this, node, options, height);
+    info.panels.push(panel);
+
+    this.setSize();
+    if (options.stable && isAtTop(this, node))
+      this.scrollTo(null, this.getScrollInfo().top + height);
+
+    return panel;
   });
 
   function Panel(cm, node, options, height) {
@@ -56,22 +56,23 @@
     this.cleared = false;
   }
 
-  Panel.prototype.clear = function() {
+  /* when skipRemove is true, clear() was called from addPanel().
+   * Thus removePanels() should not be called (issue 5518) */
+  Panel.prototype.clear = function (skipRemove) {
     if (this.cleared) return;
     this.cleared = true;
     var info = this.cm.state.panels;
-    this.cm._setSize(null, info.heightLeft += this.height);
+    info.panels.splice(info.panels.indexOf(this), 1);
+    this.cm.setSize();
     if (this.options.stable && isAtTop(this.cm, this.node))
       this.cm.scrollTo(null, this.cm.getScrollInfo().top - this.height)
     info.wrapper.removeChild(this.node);
-    if (--info.panels == 0) removePanels(this.cm);
+    if (info.panels.length == 0 && !skipRemove) removePanels(this.cm);
   };
 
-  Panel.prototype.changed = function(height) {
-    var newHeight = height == null ? this.node.offsetHeight : height;
-    var info = this.cm.state.panels;
-    this.cm._setSize(null, info.heightLeft -= (newHeight - this.height));
-    this.height = newHeight;
+  Panel.prototype.changed = function () {
+    this.height = this.node.getBoundingClientRect().height;
+    this.cm.setSize();
   };
 
   function initPanels(cm) {
@@ -80,8 +81,7 @@
     var height = parseInt(style.height);
     var info = cm.state.panels = {
       setHeight: wrap.style.height,
-      heightLeft: height,
-      panels: 0,
+      panels: [],
       wrapper: document.createElement("div")
     };
     wrap.parentNode.insertBefore(info.wrapper, wrap);
@@ -90,8 +90,8 @@
     if (hasFocus) cm.focus();
 
     cm._setSize = cm.setSize;
-    if (height != null) cm.setSize = function(width, newHeight) {
-      if (newHeight == null) return this._setSize(width, newHeight);
+    if (height != null) cm.setSize = function (width, newHeight) {
+      if (!newHeight) newHeight = info.wrapper.offsetHeight;
       info.setHeight = newHeight;
       if (typeof newHeight != "number") {
         var px = /^(\d+\.?\d*)px$/.exec(newHeight);
@@ -100,10 +100,12 @@
         } else {
           info.wrapper.style.height = newHeight;
           newHeight = info.wrapper.offsetHeight;
-          info.wrapper.style.height = "";
         }
       }
-      cm._setSize(width, info.heightLeft += (newHeight - height));
+      var editorheight = newHeight - info.panels
+        .map(function (p) { return p.node.getBoundingClientRect().height; })
+        .reduce(function (a, b) { return a + b; }, 0);
+      cm._setSize(width, editorheight);
       height = newHeight;
     };
   }
diff --git a/scripts/codemirror/addon/display/placeholder.js b/scripts/codemirror/addon/display/placeholder.js
index 1a3fa33..89bb93f 100644
--- a/scripts/codemirror/addon/display/placeholder.js
+++ b/scripts/codemirror/addon/display/placeholder.js
@@ -15,11 +15,13 @@
       cm.on("blur", onBlur);
       cm.on("change", onChange);
       cm.on("swapDoc", onChange);
+      CodeMirror.on(cm.getInputField(), "compositionupdate", cm.state.placeholderCompose = function() { onComposition(cm) })
       onChange(cm);
     } else if (!val && prev) {
       cm.off("blur", onBlur);
       cm.off("change", onChange);
       cm.off("swapDoc", onChange);
+      CodeMirror.off(cm.getInputField(), "compositionupdate", cm.state.placeholderCompose)
       clearPlaceholder(cm);
       var wrapper = cm.getWrapperElement();
       wrapper.className = wrapper.className.replace(" CodeMirror-empty", "");
@@ -39,13 +41,25 @@
     var elt = cm.state.placeholder = document.createElement("pre");
     elt.style.cssText = "height: 0; overflow: visible";
     elt.style.direction = cm.getOption("direction");
-    elt.className = "CodeMirror-placeholder";
+    elt.className = "CodeMirror-placeholder CodeMirror-line-like";
     var placeHolder = cm.getOption("placeholder")
     if (typeof placeHolder == "string") placeHolder = document.createTextNode(placeHolder)
     elt.appendChild(placeHolder)
     cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild);
   }
 
+  function onComposition(cm) {
+    setTimeout(function() {
+      var empty = false, input = cm.getInputField()
+      if (input.nodeName == "TEXTAREA")
+        empty = !input.value
+      else if (cm.lineCount() == 1)
+        empty = !/[^\u200b]/.test(input.querySelector(".CodeMirror-line").textContent)
+      if (empty) setPlaceholder(cm)
+      else clearPlaceholder(cm)
+    }, 20)
+  }
+
   function onBlur(cm) {
     if (isEmpty(cm)) setPlaceholder(cm);
   }
diff --git a/scripts/codemirror/addon/edit/closetag.js b/scripts/codemirror/addon/edit/closetag.js
index e5e83bc..8689765 100644
--- a/scripts/codemirror/addon/edit/closetag.js
+++ b/scripts/codemirror/addon/edit/closetag.js
@@ -40,9 +40,9 @@
       cm.removeKeyMap("autoCloseTags");
     if (!val) return;
     var map = {name: "autoCloseTags"};
-    if (typeof val != "object" || val.whenClosing)
+    if (typeof val != "object" || val.whenClosing !== false)
       map["'/'"] = function(cm) { return autoCloseSlash(cm); };
-    if (typeof val != "object" || val.whenOpening)
+    if (typeof val != "object" || val.whenOpening !== false)
       map["'>'"] = function(cm) { return autoCloseGT(cm); };
     cm.addKeyMap(map);
   });
@@ -60,22 +60,23 @@
       if (!ranges[i].empty()) return CodeMirror.Pass;
       var pos = ranges[i].head, tok = cm.getTokenAt(pos);
       var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
-      if (inner.mode.name != "xml" || !state.tagName) return CodeMirror.Pass;
+      var tagInfo = inner.mode.xmlCurrentTag && inner.mode.xmlCurrentTag(state)
+      var tagName = tagInfo && tagInfo.name
+      if (!tagName) return CodeMirror.Pass
 
       var html = inner.mode.configuration == "html";
       var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose);
       var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent);
 
-      var tagName = state.tagName;
       if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch);
       var lowerTagName = tagName.toLowerCase();
       // Don't process the '>' at the end of an end-tag or self-closing tag
       if (!tagName ||
           tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) ||
-          tok.type == "tag" && state.type == "closeTag" ||
-          tok.string.indexOf("/") == (tok.string.length - 1) || // match something like 
+          tok.type == "tag" && tagInfo.close ||
+          tok.string.indexOf("/") == (pos.ch - tok.start - 1) || // match something like 
           dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 ||
-          closingTagExists(cm, tagName, pos, state, true))
+          closingTagExists(cm, inner.mode.xmlCurrentContext && inner.mode.xmlCurrentContext(state) || [], tagName, pos, true))
         return CodeMirror.Pass;
 
       var emptyTags = typeof opt == "object" && opt.emptyTags;
@@ -120,19 +121,16 @@
       // when completing in JS/CSS snippet in htmlmixed mode. Does not
       // work for other XML embedded languages (there is no general
       // way to go from a mixed mode to its current XML state).
-      var replacement;
-      if (inner.mode.name != "xml") {
-        if (cm.getMode().name == "htmlmixed" && inner.mode.name == "javascript")
-          replacement = head + "script";
-        else if (cm.getMode().name == "htmlmixed" && inner.mode.name == "css")
-          replacement = head + "style";
-        else
-          return CodeMirror.Pass;
+      var replacement, mixed = inner.mode.name != "xml" && cm.getMode().name == "htmlmixed"
+      if (mixed && inner.mode.name == "javascript") {
+        replacement = head + "script";
+      } else if (mixed && inner.mode.name == "css") {
+        replacement = head + "style";
       } else {
-        if (!state.context || !state.context.tagName ||
-            closingTagExists(cm, state.context.tagName, pos, state))
+        var context = inner.mode.xmlCurrentContext && inner.mode.xmlCurrentContext(state)
+        if (!context || (context.length && closingTagExists(cm, context, context[context.length - 1], pos)))
           return CodeMirror.Pass;
-        replacement = head + state.context.tagName;
+        replacement = head + context[context.length - 1]
       }
       if (cm.getLine(pos.line).charAt(tok.end) != ">") replacement += ">";
       replacements[i] = replacement;
@@ -162,16 +160,19 @@
 
   // If xml-fold is loaded, we use its functionality to try and verify
   // whether a given tag is actually unclosed.
-  function closingTagExists(cm, tagName, pos, state, newTag) {
+  function closingTagExists(cm, context, tagName, pos, newTag) {
     if (!CodeMirror.scanForClosingTag) return false;
     var end = Math.min(cm.lastLine() + 1, pos.line + 500);
     var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end);
     if (!nextClose || nextClose.tag != tagName) return false;
-    var cx = state.context;
     // If the immediate wrapping context contains onCx instances of
     // the same tag, a closing tag only exists if there are at least
     // that many closing tags of that type following.
-    for (var onCx = newTag ? 1 : 0; cx && cx.tagName == tagName; cx = cx.prev) ++onCx;
+    var onCx = newTag ? 1 : 0
+    for (var i = context.length - 1; i >= 0; i--) {
+      if (context[i] == tagName) ++onCx
+      else break
+    }
     pos = nextClose.to;
     for (var i = 1; i < onCx; i++) {
       var next = CodeMirror.scanForClosingTag(cm, pos, null, end);
diff --git a/scripts/codemirror/addon/edit/continuelist.js b/scripts/codemirror/addon/edit/continuelist.js
index fb5f037..2e5625a 100644
--- a/scripts/codemirror/addon/edit/continuelist.js
+++ b/scripts/codemirror/addon/edit/continuelist.js
@@ -41,7 +41,9 @@
         return;
       }
       if (emptyListRE.test(line)) {
-        if (!/>\s*$/.test(line)) cm.replaceRange("", {
+        var endOfQuote = inQuote && />\s*$/.test(line)
+        var endOfList = !/>\s*$/.test(line)
+        if (endOfQuote || endOfList) cm.replaceRange("", {
           line: pos.line, ch: 0
         }, {
           line: pos.line, ch: pos.ch + 1
diff --git a/scripts/codemirror/addon/edit/matchbrackets.js b/scripts/codemirror/addon/edit/matchbrackets.js
index 2a14728..2c47e07 100644
--- a/scripts/codemirror/addon/edit/matchbrackets.js
+++ b/scripts/codemirror/addon/edit/matchbrackets.js
@@ -118,16 +118,24 @@
   }
 
   CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
-    if (old && old != CodeMirror.Init) {
-      cm.off("cursorActivity", doMatchBrackets);
+    function clear(cm) {
       if (cm.state.matchBrackets && cm.state.matchBrackets.currentlyHighlighted) {
         cm.state.matchBrackets.currentlyHighlighted();
         cm.state.matchBrackets.currentlyHighlighted = null;
       }
     }
+
+    if (old && old != CodeMirror.Init) {
+      cm.off("cursorActivity", doMatchBrackets);
+      cm.off("focus", doMatchBrackets)
+      cm.off("blur", clear)
+      clear(cm);
+    }
     if (val) {
       cm.state.matchBrackets = typeof val == "object" ? val : {};
       cm.on("cursorActivity", doMatchBrackets);
+      cm.on("focus", doMatchBrackets)
+      cm.on("blur", clear)
     }
   });
 
diff --git a/scripts/codemirror/addon/fold/foldcode.js b/scripts/codemirror/addon/fold/foldcode.js
index e146fb9..887df3f 100644
--- a/scripts/codemirror/addon/fold/foldcode.js
+++ b/scripts/codemirror/addon/fold/foldcode.js
@@ -42,7 +42,7 @@
     }
     if (!range || range.cleared || force === "unfold") return;
 
-    var myWidget = makeWidget(cm, options);
+    var myWidget = makeWidget(cm, options, range);
     CodeMirror.on(myWidget, "mousedown", function(e) {
       myRange.clear();
       CodeMirror.e_preventDefault(e);
@@ -58,8 +58,13 @@
     CodeMirror.signal(cm, "fold", cm, range.from, range.to);
   }
 
-  function makeWidget(cm, options) {
+  function makeWidget(cm, options, range) {
     var widget = getOption(cm, options, "widget");
+
+    if (typeof widget == "function") {
+      widget = widget(range.from, range.to);
+    }
+
     if (typeof widget == "string") {
       var text = document.createTextNode(widget);
       widget = document.createElement("span");
diff --git a/scripts/codemirror/addon/fold/foldgutter.js b/scripts/codemirror/addon/fold/foldgutter.js
index 988c67c..7d46a60 100644
--- a/scripts/codemirror/addon/fold/foldgutter.js
+++ b/scripts/codemirror/addon/fold/foldgutter.js
@@ -16,7 +16,7 @@
       cm.clearGutter(cm.state.foldGutter.options.gutter);
       cm.state.foldGutter = null;
       cm.off("gutterClick", onGutterClick);
-      cm.off("change", onChange);
+      cm.off("changes", onChange);
       cm.off("viewportChange", onViewportChange);
       cm.off("fold", onFold);
       cm.off("unfold", onFold);
@@ -26,7 +26,7 @@
       cm.state.foldGutter = new State(parseOptions(val));
       updateInViewport(cm);
       cm.on("gutterClick", onGutterClick);
-      cm.on("change", onChange);
+      cm.on("changes", onChange);
       cm.on("viewportChange", onViewportChange);
       cm.on("fold", onFold);
       cm.on("unfold", onFold);
@@ -51,8 +51,13 @@
 
   function isFolded(cm, line) {
     var marks = cm.findMarks(Pos(line, 0), Pos(line + 1, 0));
-    for (var i = 0; i < marks.length; ++i)
-      if (marks[i].__isFold && marks[i].find().from.line == line) return marks[i];
+    for (var i = 0; i < marks.length; ++i) {
+      if (marks[i].__isFold) {
+        var fromPos = marks[i].find(-1);
+        if (fromPos && fromPos.line === line)
+          return marks[i];
+      }
+    }
   }
 
   function marker(spec) {
@@ -66,24 +71,36 @@
   }
 
   function updateFoldInfo(cm, from, to) {
-    var opts = cm.state.foldGutter.options, cur = from;
+    var opts = cm.state.foldGutter.options, cur = from - 1;
     var minSize = cm.foldOption(opts, "minFoldSize");
     var func = cm.foldOption(opts, "rangeFinder");
+    // we can reuse the built-in indicator element if its className matches the new state
+    var clsFolded = typeof opts.indicatorFolded == "string" && classTest(opts.indicatorFolded);
+    var clsOpen = typeof opts.indicatorOpen == "string" && classTest(opts.indicatorOpen);
     cm.eachLine(from, to, function(line) {
+      ++cur;
       var mark = null;
+      var old = line.gutterMarkers;
+      if (old) old = old[opts.gutter];
       if (isFolded(cm, cur)) {
+        if (clsFolded && old && clsFolded.test(old.className)) return;
         mark = marker(opts.indicatorFolded);
       } else {
         var pos = Pos(cur, 0);
         var range = func && func(cm, pos);
-        if (range && range.to.line - range.from.line >= minSize)
+        if (range && range.to.line - range.from.line >= minSize) {
+          if (clsOpen && old && clsOpen.test(old.className)) return;
           mark = marker(opts.indicatorOpen);
+        }
       }
+      if (!mark && !old) return;
       cm.setGutterMarker(line, opts.gutter, mark);
-      ++cur;
     });
   }
 
+  // copied from CodeMirror/src/util/dom.js
+  function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") }
+
   function updateInViewport(cm) {
     var vp = cm.getViewport(), state = cm.state.foldGutter;
     if (!state) return;
@@ -100,7 +117,7 @@
     if (gutter != opts.gutter) return;
     var folded = isFolded(cm, line);
     if (folded) folded.clear();
-    else cm.foldCode(Pos(line, 0), opts.rangeFinder);
+    else cm.foldCode(Pos(line, 0), opts);
   }
 
   function onChange(cm) {
diff --git a/scripts/codemirror/addon/hint/css-hint.js b/scripts/codemirror/addon/hint/css-hint.js
index 6cdf728..980d119 100644
--- a/scripts/codemirror/addon/hint/css-hint.js
+++ b/scripts/codemirror/addon/hint/css-hint.js
@@ -11,9 +11,15 @@
 })(function(CodeMirror) {
   "use strict";
 
-  var pseudoClasses = {link: 1, visited: 1, active: 1, hover: 1, focus: 1,
-                       "first-letter": 1, "first-line": 1, "first-child": 1,
-                       before: 1, after: 1, lang: 1};
+  var pseudoClasses = {"active":1, "after":1, "before":1, "checked":1, "default":1,
+    "disabled":1, "empty":1, "enabled":1, "first-child":1, "first-letter":1,
+    "first-line":1, "first-of-type":1, "focus":1, "hover":1, "in-range":1,
+    "indeterminate":1, "invalid":1, "lang":1, "last-child":1, "last-of-type":1,
+    "link":1, "not":1, "nth-child":1, "nth-last-child":1, "nth-last-of-type":1,
+    "nth-of-type":1, "only-of-type":1, "only-child":1, "optional":1, "out-of-range":1,
+    "placeholder":1, "read-only":1, "read-write":1, "required":1, "root":1,
+    "selection":1, "target":1, "valid":1, "visited":1
+  };
 
   CodeMirror.registerHelper("hint", "css", function(cm) {
     var cur = cm.getCursor(), token = cm.getTokenAt(cur);
diff --git a/scripts/codemirror/addon/hint/javascript-hint.js b/scripts/codemirror/addon/hint/javascript-hint.js
index 96a7fe0..6d09e6b 100644
--- a/scripts/codemirror/addon/hint/javascript-hint.js
+++ b/scripts/codemirror/addon/hint/javascript-hint.js
@@ -144,10 +144,15 @@
         base = base[context.pop().string];
       if (base != null) gatherCompletions(base);
     } else {
-      // If not, just look in the global object and any local scope
+      // If not, just look in the global object, any local scope, and optional additional-context
       // (reading into JS mode internals to get at the local and global variables)
       for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
+      for (var c = token.state.context; c; c = c.prev)
+        for (var v = c.vars; v; v = v.next) maybeAdd(v.name)
       for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name);
+      if (options && options.additionalContext != null)
+        for (var key in options.additionalContext)
+          maybeAdd(key);
       if (!options || options.useGlobalScope !== false)
         gatherCompletions(global);
       forEach(keywords, maybeAdd);
diff --git a/scripts/codemirror/addon/hint/show-hint.js b/scripts/codemirror/addon/hint/show-hint.js
index d70b2ab..cd0d6a7 100644
--- a/scripts/codemirror/addon/hint/show-hint.js
+++ b/scripts/codemirror/addon/hint/show-hint.js
@@ -85,11 +85,16 @@
     },
 
     pick: function(data, i) {
-      var completion = data.list[i];
-      if (completion.hint) completion.hint(this.cm, data, completion);
-      else this.cm.replaceRange(getText(completion), completion.from || data.from,
-                                completion.to || data.to, "complete");
-      CodeMirror.signal(data, "pick", completion);
+      var completion = data.list[i], self = this;
+      this.cm.operation(function() {
+        if (completion.hint)
+          completion.hint(self.cm, data, completion);
+        else
+          self.cm.replaceRange(getText(completion), completion.from || data.from,
+                               completion.to || data.to, "complete");
+        CodeMirror.signal(data, "pick", completion);
+        self.cm.scrollIntoView();
+      })
       this.close();
     },
 
@@ -99,9 +104,14 @@
         this.debounce = 0;
       }
 
+      var identStart = this.startPos;
+      if(this.data) {
+        identStart = this.data.from;
+      }
+
       var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line);
       if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch ||
-          pos.ch < this.startPos.ch || this.cm.somethingSelected() ||
+          pos.ch < identStart.ch || this.cm.somethingSelected() ||
           (!pos.ch || this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) {
         this.close();
       } else {
@@ -322,6 +332,7 @@
     CodeMirror.on(hints, "mousedown", function() {
       setTimeout(function(){cm.focus();}, 20);
     });
+    this.scrollToActive()
 
     CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]);
     return true;
@@ -363,13 +374,21 @@
       if (node) node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, "");
       node = this.hints.childNodes[this.selectedHint = i];
       node.className += " " + ACTIVE_HINT_ELEMENT_CLASS;
-      if (node.offsetTop < this.hints.scrollTop)
-        this.hints.scrollTop = node.offsetTop - 3;
-      else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)
-        this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3;
+      this.scrollToActive()
       CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node);
     },
 
+    scrollToActive: function() {
+      var margin = this.completion.options.scrollMargin || 0;
+      var node1 = this.hints.childNodes[Math.max(0, this.selectedHint - margin)];
+      var node2 = this.hints.childNodes[Math.min(this.data.list.length - 1, this.selectedHint + margin)];
+      var firstNode = this.hints.firstChild;
+      if (node1.offsetTop < this.hints.scrollTop)
+        this.hints.scrollTop = node1.offsetTop - firstNode.offsetTop;
+      else if (node2.offsetTop + node2.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)
+        this.hints.scrollTop = node2.offsetTop + node2.offsetHeight - this.hints.clientHeight + firstNode.offsetTop;
+    },
+
     screenAmount: function() {
       return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1;
     }
diff --git a/scripts/codemirror/addon/hint/sql-hint.js b/scripts/codemirror/addon/hint/sql-hint.js
index 444eba8..de84707 100644
--- a/scripts/codemirror/addon/hint/sql-hint.js
+++ b/scripts/codemirror/addon/hint/sql-hint.js
@@ -264,7 +264,7 @@
       token.string = token.string.slice(0, cur.ch - token.start);
     }
 
-    if (token.string.match(/^[.`"\w@]\w*$/)) {
+    if (token.string.match(/^[.`"'\w@][\w$#]*$/g)) {
       search = token.string;
       start = token.start;
       end = token.end;
diff --git a/scripts/codemirror/addon/hint/xml-hint.js b/scripts/codemirror/addon/hint/xml-hint.js
index 106ba4f..543d19b 100644
--- a/scripts/codemirror/addon/hint/xml-hint.js
+++ b/scripts/codemirror/addon/hint/xml-hint.js
@@ -29,7 +29,7 @@
       token.string = token.string.slice(0, cur.ch - token.start);
     }
     var inner = CodeMirror.innerMode(cm.getMode(), token.state);
-    if (inner.mode.name != "xml") return;
+    if (!inner.mode.xmlCurrentTag) return
     var result = [], replaceToken = false, prefix;
     var tag = /\btag\b/.test(token.type) && !/>$/.test(token.string);
     var tagName = tag && /^\w/.test(token.string), tagStart;
@@ -44,12 +44,15 @@
       tagType = "close";
     }
 
-    if (!tag && !inner.state.tagName || tagType) {
+    var tagInfo = inner.mode.xmlCurrentTag(inner.state)
+    if (!tag && !tagInfo || tagType) {
       if (tagName)
         prefix = token.string;
       replaceToken = tagType;
-      var cx = inner.state.context, curTag = cx && tags[cx.tagName];
-      var childList = cx ? curTag && curTag.children : tags["!top"];
+      var context = inner.mode.xmlCurrentContext ? inner.mode.xmlCurrentContext(inner.state) : []
+      var inner = context.length && context[context.length - 1]
+      var curTag = inner && tags[inner]
+      var childList = inner ? curTag && curTag.children : tags["!top"];
       if (childList && tagType != "close") {
         for (var i = 0; i < childList.length; ++i) if (!prefix || matches(childList[i], prefix, matchInMiddle))
           result.push("<" + childList[i]);
@@ -58,11 +61,11 @@
           if (tags.hasOwnProperty(name) && name != "!top" && name != "!attrs" && (!prefix || matches(name, prefix, matchInMiddle)))
             result.push("<" + name);
       }
-      if (cx && (!prefix || tagType == "close" && matches(cx.tagName, prefix, matchInMiddle)))
-        result.push("");
+      if (inner && (!prefix || tagType == "close" && matches(inner, prefix, matchInMiddle)))
+        result.push("");
     } else {
       // Attribute completion
-      var curTag = tags[inner.state.tagName], attrs = curTag && curTag.attrs;
+      var curTag = tagInfo && tags[tagInfo.name], attrs = curTag && curTag.attrs;
       var globalAttrs = tags["!attrs"];
       if (!attrs && !globalAttrs) return;
       if (!attrs) {
@@ -98,8 +101,14 @@
           }
           replaceToken = true;
         }
-        for (var i = 0; i < atValues.length; ++i) if (!prefix || matches(atValues[i], prefix, matchInMiddle))
-          result.push(quote + atValues[i] + quote);
+        function returnHintsFromAtValues(atValues) {
+          if (atValues)
+            for (var i = 0; i < atValues.length; ++i) if (!prefix || matches(atValues[i], prefix, matchInMiddle))
+              result.push(quote + atValues[i] + quote);
+          return returnHints();
+        }
+        if (atValues && atValues.then) return atValues.then(returnHintsFromAtValues);
+        return returnHintsFromAtValues(atValues);
       } else { // An attribute name
         if (token.type == "attribute") {
           prefix = token.string;
@@ -109,11 +118,14 @@
           result.push(attr);
       }
     }
-    return {
-      list: result,
-      from: replaceToken ? Pos(cur.line, tagStart == null ? token.start : tagStart) : cur,
-      to: replaceToken ? Pos(cur.line, token.end) : cur
-    };
+    function returnHints() {
+      return {
+        list: result,
+        from: replaceToken ? Pos(cur.line, tagStart == null ? token.start : tagStart) : cur,
+        to: replaceToken ? Pos(cur.line, token.end) : cur
+      };
+    }
+    return returnHints();
   }
 
   CodeMirror.registerHelper("hint", "xml", getHints);
diff --git a/scripts/codemirror/addon/lint/lint.css b/scripts/codemirror/addon/lint/lint.css
index f097cfe..0871865 100644
--- a/scripts/codemirror/addon/lint/lint.css
+++ b/scripts/codemirror/addon/lint/lint.css
@@ -25,22 +25,20 @@
   -ms-transition: opacity .4s;
 }
 
-.CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning {
+.CodeMirror-lint-mark {
   background-position: left bottom;
   background-repeat: repeat-x;
 }
 
-.CodeMirror-lint-mark-error {
-  background-image:
-  url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==")
-  ;
-}
-
 .CodeMirror-lint-mark-warning {
   background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII=");
 }
 
-.CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning {
+.CodeMirror-lint-mark-error {
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==");
+}
+
+.CodeMirror-lint-marker {
   background-position: center center;
   background-repeat: no-repeat;
   cursor: pointer;
@@ -51,20 +49,20 @@
   position: relative;
 }
 
-.CodeMirror-lint-message-error, .CodeMirror-lint-message-warning {
+.CodeMirror-lint-message {
   padding-left: 18px;
   background-position: top left;
   background-repeat: no-repeat;
 }
 
-.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error {
-  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII=");
-}
-
 .CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning {
   background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII=");
 }
 
+.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error {
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII=");
+}
+
 .CodeMirror-lint-marker-multiple {
   background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC");
   background-repeat: no-repeat;
diff --git a/scripts/codemirror/addon/lint/lint.js b/scripts/codemirror/addon/lint/lint.js
index aa75ba0..963f2cf 100644
--- a/scripts/codemirror/addon/lint/lint.js
+++ b/scripts/codemirror/addon/lint/lint.js
@@ -12,11 +12,14 @@
   "use strict";
   var GUTTER_ID = "CodeMirror-lint-markers";
 
-  function showTooltip(e, content) {
+  function showTooltip(cm, e, content) {
     var tt = document.createElement("div");
-    tt.className = "CodeMirror-lint-tooltip";
+    tt.className = "CodeMirror-lint-tooltip cm-s-" + cm.options.theme;
     tt.appendChild(content.cloneNode(true));
-    document.body.appendChild(tt);
+    if (cm.state.lint.options.selfContain)
+      cm.getWrapperElement().appendChild(tt);
+    else
+      document.body.appendChild(tt);
 
     function position(e) {
       if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position);
@@ -38,8 +41,8 @@
     setTimeout(function() { rm(tt); }, 600);
   }
 
-  function showTooltipFor(e, content, node) {
-    var tooltip = showTooltip(e, content);
+  function showTooltipFor(cm, e, content, node) {
+    var tooltip = showTooltip(cm, e, content);
     function hide() {
       CodeMirror.off(node, "mouseout", hide);
       if (tooltip) { hideTooltip(tooltip); tooltip = null; }
@@ -78,16 +81,16 @@
     state.marked.length = 0;
   }
 
-  function makeMarker(labels, severity, multiple, tooltips) {
+  function makeMarker(cm, labels, severity, multiple, tooltips) {
     var marker = document.createElement("div"), inner = marker;
-    marker.className = "CodeMirror-lint-marker-" + severity;
+    marker.className = "CodeMirror-lint-marker CodeMirror-lint-marker-" + severity;
     if (multiple) {
       inner = marker.appendChild(document.createElement("div"));
-      inner.className = "CodeMirror-lint-marker-multiple";
+      inner.className = "CodeMirror-lint-marker CodeMirror-lint-marker-multiple";
     }
 
     if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) {
-      showTooltipFor(e, labels, inner);
+      showTooltipFor(cm, e, labels, inner);
     });
 
     return marker;
@@ -111,11 +114,11 @@
     var severity = ann.severity;
     if (!severity) severity = "error";
     var tip = document.createElement("div");
-    tip.className = "CodeMirror-lint-message-" + severity;
+    tip.className = "CodeMirror-lint-message CodeMirror-lint-message-" + severity;
     if (typeof ann.messageHTML != 'undefined') {
-        tip.innerHTML = ann.messageHTML;
+      tip.innerHTML = ann.messageHTML;
     } else {
-        tip.appendChild(document.createTextNode(ann.message));
+      tip.appendChild(document.createTextNode(ann.message));
     }
     return tip;
   }
@@ -180,13 +183,13 @@
         if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann));
 
         if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, {
-          className: "CodeMirror-lint-mark-" + severity,
+          className: "CodeMirror-lint-mark CodeMirror-lint-mark-" + severity,
           __annotation: ann
         }));
       }
 
       if (state.hasGutter)
-        cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1,
+        cm.setGutterMarker(line, GUTTER_ID, makeMarker(cm, tipLabel, maxSeverity, anns.length > 1,
                                                        state.options.tooltips));
     }
     if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm);
@@ -199,14 +202,14 @@
     state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500);
   }
 
-  function popupTooltips(annotations, e) {
+  function popupTooltips(cm, annotations, e) {
     var target = e.target || e.srcElement;
     var tooltip = document.createDocumentFragment();
     for (var i = 0; i < annotations.length; i++) {
       var ann = annotations[i];
       tooltip.appendChild(annotationTooltip(ann));
     }
-    showTooltipFor(e, tooltip, target);
+    showTooltipFor(cm, e, tooltip, target);
   }
 
   function onMouseOver(cm, e) {
@@ -220,7 +223,7 @@
       var ann = spans[i].__annotation;
       if (ann) annotations.push(ann);
     }
-    if (annotations.length) popupTooltips(annotations, e);
+    if (annotations.length) popupTooltips(cm, annotations, e);
   }
 
   CodeMirror.defineOption("lint", false, function(cm, val, old) {
diff --git a/scripts/codemirror/addon/merge/merge.js b/scripts/codemirror/addon/merge/merge.js
index 8296540..827edb7 100644
--- a/scripts/codemirror/addon/merge/merge.js
+++ b/scripts/codemirror/addon/merge/merge.js
@@ -443,22 +443,26 @@
       aligners[i].clear();
     aligners.length = 0;
 
-    var cm = [dv.edit, dv.orig], scroll = [];
+    var cm = [dv.edit, dv.orig], scroll = [], offset = []
     if (other) cm.push(other.orig);
-    for (var i = 0; i < cm.length; i++)
+    for (var i = 0; i < cm.length; i++) {
       scroll.push(cm[i].getScrollInfo().top);
+      offset.push(-cm[i].getScrollerElement().getBoundingClientRect().top)
+    }
 
+    if (offset[0] != offset[1] || cm.length == 3 && offset[1] != offset[2])
+      alignLines(cm, offset, [0, 0, 0], aligners)
     for (var ln = 0; ln < linesToAlign.length; ln++)
-      alignLines(cm, linesToAlign[ln], aligners);
+      alignLines(cm, offset, linesToAlign[ln], aligners);
 
     for (var i = 0; i < cm.length; i++)
       cm[i].scrollTo(null, scroll[i]);
   }
 
-  function alignLines(cm, lines, aligners) {
-    var maxOffset = 0, offset = [];
+  function alignLines(cm, cmOffset, lines, aligners) {
+    var maxOffset = -1e8, offset = [];
     for (var i = 0; i < cm.length; i++) if (lines[i] != null) {
-      var off = cm[i].heightAtLine(lines[i], "local");
+      var off = cm[i].heightAtLine(lines[i], "local") - cmOffset[i];
       offset[i] = off;
       maxOffset = Math.max(maxOffset, off);
     }
diff --git a/scripts/codemirror/addon/mode/loadmode.js b/scripts/codemirror/addon/mode/loadmode.js
index 4ce716a..fc695d0 100644
--- a/scripts/codemirror/addon/mode/loadmode.js
+++ b/scripts/codemirror/addon/mode/loadmode.js
@@ -16,8 +16,8 @@
     var countDown = n;
     return function() { if (--countDown == 0) cont(); };
   }
-  function ensureDeps(mode, cont) {
-    var deps = CodeMirror.modes[mode].dependencies;
+  function ensureDeps(mode, cont, options) {
+    var modeObj = CodeMirror.modes[mode], deps = modeObj && modeObj.dependencies;
     if (!deps) return cont();
     var missing = [];
     for (var i = 0; i < deps.length; ++i) {
@@ -27,16 +27,18 @@
     if (!missing.length) return cont();
     var split = splitCallback(cont, missing.length);
     for (var i = 0; i < missing.length; ++i)
-      CodeMirror.requireMode(missing[i], split);
+      CodeMirror.requireMode(missing[i], split, options);
   }
 
-  CodeMirror.requireMode = function(mode, cont) {
+  CodeMirror.requireMode = function(mode, cont, options) {
     if (typeof mode != "string") mode = mode.name;
-    if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont);
+    if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont, options);
     if (loading.hasOwnProperty(mode)) return loading[mode].push(cont);
 
-    var file = CodeMirror.modeURL.replace(/%N/g, mode);
-    if (env == "plain") {
+    var file = options && options.path ? options.path(mode) : CodeMirror.modeURL.replace(/%N/g, mode);
+    if (options && options.loadMode) {
+      options.loadMode(file, function() { ensureDeps(mode, cont, options) })
+    } else if (env == "plain") {
       var script = document.createElement("script");
       script.src = file;
       var others = document.getElementsByTagName("script")[0];
@@ -44,7 +46,7 @@
       CodeMirror.on(script, "load", function() {
         ensureDeps(mode, function() {
           for (var i = 0; i < list.length; ++i) list[i]();
-        });
+        }, options);
       });
       others.parentNode.insertBefore(script, others);
     } else if (env == "cjs") {
@@ -55,10 +57,10 @@
     }
   };
 
-  CodeMirror.autoLoadMode = function(instance, mode) {
+  CodeMirror.autoLoadMode = function(instance, mode, options) {
     if (!CodeMirror.modes.hasOwnProperty(mode))
       CodeMirror.requireMode(mode, function() {
         instance.setOption("mode", instance.getOption("mode"));
-      });
+      }, options);
   };
 });
diff --git a/scripts/codemirror/addon/runmode/runmode-standalone.js b/scripts/codemirror/addon/runmode/runmode-standalone.js
index 745eaf8..e71041c 100644
--- a/scripts/codemirror/addon/runmode/runmode-standalone.js
+++ b/scripts/codemirror/addon/runmode/runmode-standalone.js
@@ -1,158 +1,333 @@
-// CodeMirror, copyright (c) by Marijn Haverbeke and others
-// Distributed under an MIT license: https://codemirror.net/LICENSE
+(function () {
+  'use strict';
 
-window.CodeMirror = {};
+  function copyObj(obj, target, overwrite) {
+    if (!target) { target = {}; }
+    for (var prop in obj)
+      { if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
+        { target[prop] = obj[prop]; } }
+    return target
+  }
 
-(function() {
-"use strict";
+  // Counts the column offset in a string, taking tabs into account.
+  // Used mostly to find indentation.
+  function countColumn(string, end, tabSize, startIndex, startValue) {
+    if (end == null) {
+      end = string.search(/[^\s\u00a0]/);
+      if (end == -1) { end = string.length; }
+    }
+    for (var i = startIndex || 0, n = startValue || 0;;) {
+      var nextTab = string.indexOf("\t", i);
+      if (nextTab < 0 || nextTab >= end)
+        { return n + (end - i) }
+      n += nextTab - i;
+      n += tabSize - (n % tabSize);
+      i = nextTab + 1;
+    }
+  }
 
-function splitLines(string){ return string.split(/\r?\n|\r/); };
+  function nothing() {}
 
-function StringStream(string) {
-  this.pos = this.start = 0;
-  this.string = string;
-  this.lineStart = 0;
-}
-StringStream.prototype = {
-  eol: function() {return this.pos >= this.string.length;},
-  sol: function() {return this.pos == 0;},
-  peek: function() {return this.string.charAt(this.pos) || null;},
-  next: function() {
+  function createObj(base, props) {
+    var inst;
+    if (Object.create) {
+      inst = Object.create(base);
+    } else {
+      nothing.prototype = base;
+      inst = new nothing();
+    }
+    if (props) { copyObj(props, inst); }
+    return inst
+  }
+
+  // STRING STREAM
+
+  // Fed to the mode parsers, provides helper functions to make
+  // parsers more succinct.
+
+  var StringStream = function(string, tabSize, lineOracle) {
+    this.pos = this.start = 0;
+    this.string = string;
+    this.tabSize = tabSize || 8;
+    this.lastColumnPos = this.lastColumnValue = 0;
+    this.lineStart = 0;
+    this.lineOracle = lineOracle;
+  };
+
+  StringStream.prototype.eol = function () {return this.pos >= this.string.length};
+  StringStream.prototype.sol = function () {return this.pos == this.lineStart};
+  StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined};
+  StringStream.prototype.next = function () {
     if (this.pos < this.string.length)
-      return this.string.charAt(this.pos++);
-  },
-  eat: function(match) {
+      { return this.string.charAt(this.pos++) }
+  };
+  StringStream.prototype.eat = function (match) {
     var ch = this.string.charAt(this.pos);
-    if (typeof match == "string") var ok = ch == match;
-    else var ok = ch && (match.test ? match.test(ch) : match(ch));
-    if (ok) {++this.pos; return ch;}
-  },
-  eatWhile: function(match) {
+    var ok;
+    if (typeof match == "string") { ok = ch == match; }
+    else { ok = ch && (match.test ? match.test(ch) : match(ch)); }
+    if (ok) {++this.pos; return ch}
+  };
+  StringStream.prototype.eatWhile = function (match) {
     var start = this.pos;
     while (this.eat(match)){}
-    return this.pos > start;
-  },
-  eatSpace: function() {
+    return this.pos > start
+  };
+  StringStream.prototype.eatSpace = function () {
     var start = this.pos;
-    while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
-    return this.pos > start;
-  },
-  skipToEnd: function() {this.pos = this.string.length;},
-  skipTo: function(ch) {
+    while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this.pos; }
+    return this.pos > start
+  };
+  StringStream.prototype.skipToEnd = function () {this.pos = this.string.length;};
+  StringStream.prototype.skipTo = function (ch) {
     var found = this.string.indexOf(ch, this.pos);
-    if (found > -1) {this.pos = found; return true;}
-  },
-  backUp: function(n) {this.pos -= n;},
-  column: function() {return this.start - this.lineStart;},
-  indentation: function() {return 0;},
-  match: function(pattern, consume, caseInsensitive) {
+    if (found > -1) {this.pos = found; return true}
+  };
+  StringStream.prototype.backUp = function (n) {this.pos -= n;};
+  StringStream.prototype.column = function () {
+    if (this.lastColumnPos < this.start) {
+      this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
+      this.lastColumnPos = this.start;
+    }
+    return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
+  };
+  StringStream.prototype.indentation = function () {
+    return countColumn(this.string, null, this.tabSize) -
+      (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
+  };
+  StringStream.prototype.match = function (pattern, consume, caseInsensitive) {
     if (typeof pattern == "string") {
-      var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
+      var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; };
       var substr = this.string.substr(this.pos, pattern.length);
       if (cased(substr) == cased(pattern)) {
-        if (consume !== false) this.pos += pattern.length;
-        return true;
+        if (consume !== false) { this.pos += pattern.length; }
+        return true
       }
     } else {
       var match = this.string.slice(this.pos).match(pattern);
-      if (match && match.index > 0) return null;
-      if (match && consume !== false) this.pos += match[0].length;
-      return match;
+      if (match && match.index > 0) { return null }
+      if (match && consume !== false) { this.pos += match[0].length; }
+      return match
     }
-  },
-  current: function(){return this.string.slice(this.start, this.pos);},
-  hideFirstChars: function(n, inner) {
+  };
+  StringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)};
+  StringStream.prototype.hideFirstChars = function (n, inner) {
     this.lineStart += n;
-    try { return inner(); }
+    try { return inner() }
     finally { this.lineStart -= n; }
-  },
-  lookAhead: function() { return null }
-};
-CodeMirror.StringStream = StringStream;
+  };
+  StringStream.prototype.lookAhead = function (n) {
+    var oracle = this.lineOracle;
+    return oracle && oracle.lookAhead(n)
+  };
+  StringStream.prototype.baseToken = function () {
+    var oracle = this.lineOracle;
+    return oracle && oracle.baseToken(this.pos)
+  };
 
-CodeMirror.startState = function (mode, a1, a2) {
-  return mode.startState ? mode.startState(a1, a2) : true;
-};
+  // Known modes, by name and by MIME
+  var modes = {}, mimeModes = {};
 
-var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
-CodeMirror.defineMode = function (name, mode) {
-  if (arguments.length > 2)
-    mode.dependencies = Array.prototype.slice.call(arguments, 2);
-  modes[name] = mode;
-};
-CodeMirror.defineMIME = function (mime, spec) { mimeModes[mime] = spec; };
-CodeMirror.resolveMode = function(spec) {
-  if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
-    spec = mimeModes[spec];
-  } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
-    spec = mimeModes[spec.name];
-  }
-  if (typeof spec == "string") return {name: spec};
-  else return spec || {name: "null"};
-};
-CodeMirror.getMode = function (options, spec) {
-  spec = CodeMirror.resolveMode(spec);
-  var mfactory = modes[spec.name];
-  if (!mfactory) throw new Error("Unknown mode: " + spec);
-  return mfactory(options, spec);
-};
-CodeMirror.registerHelper = CodeMirror.registerGlobalHelper = Math.min;
-CodeMirror.defineMode("null", function() {
-  return {token: function(stream) {stream.skipToEnd();}};
-});
-CodeMirror.defineMIME("text/plain", "null");
-
-CodeMirror.runMode = function (string, modespec, callback, options) {
-  var mode = CodeMirror.getMode({ indentUnit: 2 }, modespec);
-
-  if (callback.nodeType == 1) {
-    var tabSize = (options && options.tabSize) || 4;
-    var node = callback, col = 0;
-    node.innerHTML = "";
-    callback = function (text, style) {
-      if (text == "\n") {
-        node.appendChild(document.createElement("br"));
-        col = 0;
-        return;
-      }
-      var content = "";
-      // replace tabs
-      for (var pos = 0; ;) {
-        var idx = text.indexOf("\t", pos);
-        if (idx == -1) {
-          content += text.slice(pos);
-          col += text.length - pos;
-          break;
-        } else {
-          col += idx - pos;
-          content += text.slice(pos, idx);
-          var size = tabSize - col % tabSize;
-          col += size;
-          for (var i = 0; i < size; ++i) content += " ";
-          pos = idx + 1;
-        }
-      }
-
-      if (style) {
-        var sp = node.appendChild(document.createElement("span"));
-        sp.className = "cm-" + style.replace(/ +/g, " cm-");
-        sp.appendChild(document.createTextNode(content));
-      } else {
-        node.appendChild(document.createTextNode(content));
-      }
-    };
+  // Extra arguments are stored as the mode's dependencies, which is
+  // used by (legacy) mechanisms like loadmode.js to automatically
+  // load a mode. (Preferred mechanism is the require/define calls.)
+  function defineMode(name, mode) {
+    if (arguments.length > 2)
+      { mode.dependencies = Array.prototype.slice.call(arguments, 2); }
+    modes[name] = mode;
   }
 
-  var lines = splitLines(string), state = (options && options.state) || CodeMirror.startState(mode);
-  for (var i = 0, e = lines.length; i < e; ++i) {
-    if (i) callback("\n");
-    var stream = new CodeMirror.StringStream(lines[i]);
-    if (!stream.string && mode.blankLine) mode.blankLine(state);
-    while (!stream.eol()) {
-      var style = mode.token(stream, state);
-      callback(stream.current(), style, i, stream.start, state);
-      stream.start = stream.pos;
+  function defineMIME(mime, spec) {
+    mimeModes[mime] = spec;
+  }
+
+  // Given a MIME type, a {name, ...options} config object, or a name
+  // string, return a mode config object.
+  function resolveMode(spec) {
+    if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
+      spec = mimeModes[spec];
+    } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
+      var found = mimeModes[spec.name];
+      if (typeof found == "string") { found = {name: found}; }
+      spec = createObj(found, spec);
+      spec.name = found.name;
+    } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
+      return resolveMode("application/xml")
+    } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) {
+      return resolveMode("application/json")
     }
+    if (typeof spec == "string") { return {name: spec} }
+    else { return spec || {name: "null"} }
   }
-};
-})();
+
+  // Given a mode spec (anything that resolveMode accepts), find and
+  // initialize an actual mode object.
+  function getMode(options, spec) {
+    spec = resolveMode(spec);
+    var mfactory = modes[spec.name];
+    if (!mfactory) { return getMode(options, "text/plain") }
+    var modeObj = mfactory(options, spec);
+    if (modeExtensions.hasOwnProperty(spec.name)) {
+      var exts = modeExtensions[spec.name];
+      for (var prop in exts) {
+        if (!exts.hasOwnProperty(prop)) { continue }
+        if (modeObj.hasOwnProperty(prop)) { modeObj["_" + prop] = modeObj[prop]; }
+        modeObj[prop] = exts[prop];
+      }
+    }
+    modeObj.name = spec.name;
+    if (spec.helperType) { modeObj.helperType = spec.helperType; }
+    if (spec.modeProps) { for (var prop$1 in spec.modeProps)
+      { modeObj[prop$1] = spec.modeProps[prop$1]; } }
+
+    return modeObj
+  }
+
+  // This can be used to attach properties to mode objects from
+  // outside the actual mode definition.
+  var modeExtensions = {};
+  function extendMode(mode, properties) {
+    var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
+    copyObj(properties, exts);
+  }
+
+  function copyState(mode, state) {
+    if (state === true) { return state }
+    if (mode.copyState) { return mode.copyState(state) }
+    var nstate = {};
+    for (var n in state) {
+      var val = state[n];
+      if (val instanceof Array) { val = val.concat([]); }
+      nstate[n] = val;
+    }
+    return nstate
+  }
+
+  // Given a mode and a state (for that mode), find the inner mode and
+  // state at the position that the state refers to.
+  function innerMode(mode, state) {
+    var info;
+    while (mode.innerMode) {
+      info = mode.innerMode(state);
+      if (!info || info.mode == mode) { break }
+      state = info.state;
+      mode = info.mode;
+    }
+    return info || {mode: mode, state: state}
+  }
+
+  function startState(mode, a1, a2) {
+    return mode.startState ? mode.startState(a1, a2) : true
+  }
+
+  var modeMethods = {
+    __proto__: null,
+    modes: modes,
+    mimeModes: mimeModes,
+    defineMode: defineMode,
+    defineMIME: defineMIME,
+    resolveMode: resolveMode,
+    getMode: getMode,
+    modeExtensions: modeExtensions,
+    extendMode: extendMode,
+    copyState: copyState,
+    innerMode: innerMode,
+    startState: startState
+  };
+
+  // declare global: globalThis, CodeMirror
+
+  // Create a minimal CodeMirror needed to use runMode, and assign to root.
+  var root = typeof globalThis !== 'undefined' ? globalThis : window;
+  root.CodeMirror = {};
+
+  // Copy StringStream and mode methods into CodeMirror object.
+  CodeMirror.StringStream = StringStream;
+  for (var exported in modeMethods) { CodeMirror[exported] = modeMethods[exported]; }
+
+  // Minimal default mode.
+  CodeMirror.defineMode("null", function () { return ({token: function (stream) { return stream.skipToEnd(); }}); });
+  CodeMirror.defineMIME("text/plain", "null");
+
+  CodeMirror.registerHelper = CodeMirror.registerGlobalHelper = Math.min;
+  CodeMirror.splitLines = function(string) { return string.split(/\r?\n|\r/) };
+
+  CodeMirror.defaults = { indentUnit: 2 };
+
+  // CodeMirror, copyright (c) by Marijn Haverbeke and others
+  // Distributed under an MIT license: https://codemirror.net/LICENSE
+
+  (function(mod) {
+    if (typeof exports == "object" && typeof module == "object") // CommonJS
+      { mod(require("../../lib/codemirror")); }
+    else if (typeof define == "function" && define.amd) // AMD
+      { define(["../../lib/codemirror"], mod); }
+    else // Plain browser env
+      { mod(CodeMirror); }
+  })(function(CodeMirror) {
+
+  CodeMirror.runMode = function(string, modespec, callback, options) {
+    var mode = CodeMirror.getMode(CodeMirror.defaults, modespec);
+    var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize;
+
+    // Create a tokenizing callback function if passed-in callback is a DOM element.
+    if (callback.appendChild) {
+      var ie = /MSIE \d/.test(navigator.userAgent);
+      var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9);
+      var node = callback, col = 0;
+      node.innerHTML = "";
+      callback = function(text, style) {
+        if (text == "\n") {
+          // Emitting LF or CRLF on IE8 or earlier results in an incorrect display.
+          // Emitting a carriage return makes everything ok.
+          node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text));
+          col = 0;
+          return;
+        }
+        var content = "";
+        // replace tabs
+        for (var pos = 0;;) {
+          var idx = text.indexOf("\t", pos);
+          if (idx == -1) {
+            content += text.slice(pos);
+            col += text.length - pos;
+            break;
+          } else {
+            col += idx - pos;
+            content += text.slice(pos, idx);
+            var size = tabSize - col % tabSize;
+            col += size;
+            for (var i = 0; i < size; ++i) { content += " "; }
+            pos = idx + 1;
+          }
+        }
+        // Create a node with token style and append it to the callback DOM element.
+        if (style) {
+          var sp = node.appendChild(document.createElement("span"));
+          sp.className = "cm-" + style.replace(/ +/g, " cm-");
+          sp.appendChild(document.createTextNode(content));
+        } else {
+          node.appendChild(document.createTextNode(content));
+        }
+      };
+    }
+
+    var lines = CodeMirror.splitLines(string), state = (options && options.state) || CodeMirror.startState(mode);
+    for (var i = 0, e = lines.length; i < e; ++i) {
+      if (i) { callback("\n"); }
+      var stream = new CodeMirror.StringStream(lines[i], null, {
+        lookAhead: function(n) { return lines[i + n] },
+        baseToken: function() {}
+      });
+      if (!stream.string && mode.blankLine) { mode.blankLine(state); }
+      while (!stream.eol()) {
+        var style = mode.token(stream, state);
+        callback(stream.current(), style, i, stream.start, state);
+        stream.start = stream.pos;
+      }
+    }
+  };
+
+  });
+
+}());
diff --git a/scripts/codemirror/addon/runmode/runmode.js b/scripts/codemirror/addon/runmode/runmode.js
index eb4cadf..2cae686 100644
--- a/scripts/codemirror/addon/runmode/runmode.js
+++ b/scripts/codemirror/addon/runmode/runmode.js
@@ -13,11 +13,12 @@
 
 CodeMirror.runMode = function(string, modespec, callback, options) {
   var mode = CodeMirror.getMode(CodeMirror.defaults, modespec);
-  var ie = /MSIE \d/.test(navigator.userAgent);
-  var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9);
+  var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize;
 
+  // Create a tokenizing callback function if passed-in callback is a DOM element.
   if (callback.appendChild) {
-    var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize;
+    var ie = /MSIE \d/.test(navigator.userAgent);
+    var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9);
     var node = callback, col = 0;
     node.innerHTML = "";
     callback = function(text, style) {
@@ -45,7 +46,7 @@ CodeMirror.runMode = function(string, modespec, callback, options) {
           pos = idx + 1;
         }
       }
-
+      // Create a node with token style and append it to the callback DOM element.
       if (style) {
         var sp = node.appendChild(document.createElement("span"));
         sp.className = "cm-" + style.replace(/ +/g, " cm-");
@@ -59,7 +60,10 @@ CodeMirror.runMode = function(string, modespec, callback, options) {
   var lines = CodeMirror.splitLines(string), state = (options && options.state) || CodeMirror.startState(mode);
   for (var i = 0, e = lines.length; i < e; ++i) {
     if (i) callback("\n");
-    var stream = new CodeMirror.StringStream(lines[i]);
+    var stream = new CodeMirror.StringStream(lines[i], null, {
+      lookAhead: function(n) { return lines[i + n] },
+      baseToken: function() {}
+    });
     if (!stream.string && mode.blankLine) mode.blankLine(state);
     while (!stream.eol()) {
       var style = mode.token(stream, state);
diff --git a/scripts/codemirror/addon/runmode/runmode.node.js b/scripts/codemirror/addon/runmode/runmode.node.js
index 53b6994..92cda61 100644
--- a/scripts/codemirror/addon/runmode/runmode.node.js
+++ b/scripts/codemirror/addon/runmode/runmode.node.js
@@ -1,190 +1,323 @@
-// CodeMirror, copyright (c) by Marijn Haverbeke and others
-// Distributed under an MIT license: https://codemirror.net/LICENSE
+'use strict';
 
-/* Just enough of CodeMirror to run runMode under node.js */
-
-function splitLines(string){return string.split(/\r\n?|\n/);};
+function copyObj(obj, target, overwrite) {
+  if (!target) { target = {}; }
+  for (var prop in obj)
+    { if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
+      { target[prop] = obj[prop]; } }
+  return target
+}
 
 // Counts the column offset in a string, taking tabs into account.
 // Used mostly to find indentation.
-var countColumn = exports.countColumn = function(string, end, tabSize, startIndex, startValue) {
+function countColumn(string, end, tabSize, startIndex, startValue) {
   if (end == null) {
     end = string.search(/[^\s\u00a0]/);
-    if (end == -1) end = string.length;
+    if (end == -1) { end = string.length; }
   }
   for (var i = startIndex || 0, n = startValue || 0;;) {
     var nextTab = string.indexOf("\t", i);
     if (nextTab < 0 || nextTab >= end)
-      return n + (end - i);
+      { return n + (end - i) }
     n += nextTab - i;
     n += tabSize - (n % tabSize);
     i = nextTab + 1;
   }
-};
+}
 
-function StringStream(string, tabSize, context) {
+function nothing() {}
+
+function createObj(base, props) {
+  var inst;
+  if (Object.create) {
+    inst = Object.create(base);
+  } else {
+    nothing.prototype = base;
+    inst = new nothing();
+  }
+  if (props) { copyObj(props, inst); }
+  return inst
+}
+
+// STRING STREAM
+
+// Fed to the mode parsers, provides helper functions to make
+// parsers more succinct.
+
+var StringStream = function(string, tabSize, lineOracle) {
   this.pos = this.start = 0;
   this.string = string;
   this.tabSize = tabSize || 8;
   this.lastColumnPos = this.lastColumnValue = 0;
   this.lineStart = 0;
-  this.context = context
+  this.lineOracle = lineOracle;
 };
 
-StringStream.prototype = {
-  eol: function() {return this.pos >= this.string.length;},
-  sol: function() {return this.pos == this.lineStart;},
-  peek: function() {return this.string.charAt(this.pos) || undefined;},
-  next: function() {
-    if (this.pos < this.string.length)
-      return this.string.charAt(this.pos++);
-  },
-  eat: function(match) {
-    var ch = this.string.charAt(this.pos);
-    if (typeof match == "string") var ok = ch == match;
-    else var ok = ch && (match.test ? match.test(ch) : match(ch));
-    if (ok) {++this.pos; return ch;}
-  },
-  eatWhile: function(match) {
-    var start = this.pos;
-    while (this.eat(match)){}
-    return this.pos > start;
-  },
-  eatSpace: function() {
-    var start = this.pos;
-    while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
-    return this.pos > start;
-  },
-  skipToEnd: function() {this.pos = this.string.length;},
-  skipTo: function(ch) {
-    var found = this.string.indexOf(ch, this.pos);
-    if (found > -1) {this.pos = found; return true;}
-  },
-  backUp: function(n) {this.pos -= n;},
-  column: function() {
-    if (this.lastColumnPos < this.start) {
-      this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
-      this.lastColumnPos = this.start;
+StringStream.prototype.eol = function () {return this.pos >= this.string.length};
+StringStream.prototype.sol = function () {return this.pos == this.lineStart};
+StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined};
+StringStream.prototype.next = function () {
+  if (this.pos < this.string.length)
+    { return this.string.charAt(this.pos++) }
+};
+StringStream.prototype.eat = function (match) {
+  var ch = this.string.charAt(this.pos);
+  var ok;
+  if (typeof match == "string") { ok = ch == match; }
+  else { ok = ch && (match.test ? match.test(ch) : match(ch)); }
+  if (ok) {++this.pos; return ch}
+};
+StringStream.prototype.eatWhile = function (match) {
+  var start = this.pos;
+  while (this.eat(match)){}
+  return this.pos > start
+};
+StringStream.prototype.eatSpace = function () {
+  var start = this.pos;
+  while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this.pos; }
+  return this.pos > start
+};
+StringStream.prototype.skipToEnd = function () {this.pos = this.string.length;};
+StringStream.prototype.skipTo = function (ch) {
+  var found = this.string.indexOf(ch, this.pos);
+  if (found > -1) {this.pos = found; return true}
+};
+StringStream.prototype.backUp = function (n) {this.pos -= n;};
+StringStream.prototype.column = function () {
+  if (this.lastColumnPos < this.start) {
+    this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
+    this.lastColumnPos = this.start;
+  }
+  return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
+};
+StringStream.prototype.indentation = function () {
+  return countColumn(this.string, null, this.tabSize) -
+    (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
+};
+StringStream.prototype.match = function (pattern, consume, caseInsensitive) {
+  if (typeof pattern == "string") {
+    var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; };
+    var substr = this.string.substr(this.pos, pattern.length);
+    if (cased(substr) == cased(pattern)) {
+      if (consume !== false) { this.pos += pattern.length; }
+      return true
     }
-    return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
-  },
-  indentation: function() {
-    return countColumn(this.string, null, this.tabSize) -
-      (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
-  },
-  match: function(pattern, consume, caseInsensitive) {
-    if (typeof pattern == "string") {
-      var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
-      var substr = this.string.substr(this.pos, pattern.length);
-      if (cased(substr) == cased(pattern)) {
-        if (consume !== false) this.pos += pattern.length;
-        return true;
-      }
-    } else {
-      var match = this.string.slice(this.pos).match(pattern);
-      if (match && match.index > 0) return null;
-      if (match && consume !== false) this.pos += match[0].length;
-      return match;
-    }
-  },
-  current: function(){return this.string.slice(this.start, this.pos);},
-  hideFirstChars: function(n, inner) {
-    this.lineStart += n;
-    try { return inner(); }
-    finally { this.lineStart -= n; }
-  },
-  lookAhead: function(n) {
-    var line = this.context.line + n
-    return line >= this.context.lines.length ? null : this.context.lines[line]
+  } else {
+    var match = this.string.slice(this.pos).match(pattern);
+    if (match && match.index > 0) { return null }
+    if (match && consume !== false) { this.pos += match[0].length; }
+    return match
   }
 };
-exports.StringStream = StringStream;
-
-exports.startState = function(mode, a1, a2) {
-  return mode.startState ? mode.startState(a1, a2) : true;
+StringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)};
+StringStream.prototype.hideFirstChars = function (n, inner) {
+  this.lineStart += n;
+  try { return inner() }
+  finally { this.lineStart -= n; }
+};
+StringStream.prototype.lookAhead = function (n) {
+  var oracle = this.lineOracle;
+  return oracle && oracle.lookAhead(n)
+};
+StringStream.prototype.baseToken = function () {
+  var oracle = this.lineOracle;
+  return oracle && oracle.baseToken(this.pos)
 };
 
-var modes = exports.modes = {}, mimeModes = exports.mimeModes = {};
-exports.defineMode = function(name, mode) {
+// Known modes, by name and by MIME
+var modes = {}, mimeModes = {};
+
+// Extra arguments are stored as the mode's dependencies, which is
+// used by (legacy) mechanisms like loadmode.js to automatically
+// load a mode. (Preferred mechanism is the require/define calls.)
+function defineMode(name, mode) {
   if (arguments.length > 2)
-    mode.dependencies = Array.prototype.slice.call(arguments, 2);
+    { mode.dependencies = Array.prototype.slice.call(arguments, 2); }
   modes[name] = mode;
-};
-exports.defineMIME = function(mime, spec) { mimeModes[mime] = spec; };
+}
 
-exports.defineMode("null", function() {
-  return {token: function(stream) {stream.skipToEnd();}};
-});
-exports.defineMIME("text/plain", "null");
+function defineMIME(mime, spec) {
+  mimeModes[mime] = spec;
+}
 
-exports.resolveMode = function(spec) {
+// Given a MIME type, a {name, ...options} config object, or a name
+// string, return a mode config object.
+function resolveMode(spec) {
   if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
     spec = mimeModes[spec];
   } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
-    spec = mimeModes[spec.name];
+    var found = mimeModes[spec.name];
+    if (typeof found == "string") { found = {name: found}; }
+    spec = createObj(found, spec);
+    spec.name = found.name;
+  } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
+    return resolveMode("application/xml")
+  } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) {
+    return resolveMode("application/json")
   }
-  if (typeof spec == "string") return {name: spec};
-  else return spec || {name: "null"};
-};
-
-function copyObj(obj, target, overwrite) {
-  if (!target) target = {};
-  for (var prop in obj)
-    if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
-      target[prop] = obj[prop];
-  return target;
+  if (typeof spec == "string") { return {name: spec} }
+  else { return spec || {name: "null"} }
 }
 
-// This can be used to attach properties to mode objects from
-// outside the actual mode definition.
-var modeExtensions = exports.modeExtensions = {};
-exports.extendMode = function(mode, properties) {
-  var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
-  copyObj(properties, exts);
-};
-
-exports.getMode = function(options, spec) {
-  var spec = exports.resolveMode(spec);
+// Given a mode spec (anything that resolveMode accepts), find and
+// initialize an actual mode object.
+function getMode(options, spec) {
+  spec = resolveMode(spec);
   var mfactory = modes[spec.name];
-  if (!mfactory) return exports.getMode(options, "text/plain");
+  if (!mfactory) { return getMode(options, "text/plain") }
   var modeObj = mfactory(options, spec);
   if (modeExtensions.hasOwnProperty(spec.name)) {
     var exts = modeExtensions[spec.name];
     for (var prop in exts) {
-      if (!exts.hasOwnProperty(prop)) continue;
-      if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop];
+      if (!exts.hasOwnProperty(prop)) { continue }
+      if (modeObj.hasOwnProperty(prop)) { modeObj["_" + prop] = modeObj[prop]; }
       modeObj[prop] = exts[prop];
     }
   }
   modeObj.name = spec.name;
-  if (spec.helperType) modeObj.helperType = spec.helperType;
-  if (spec.modeProps) for (var prop in spec.modeProps)
-    modeObj[prop] = spec.modeProps[prop];
+  if (spec.helperType) { modeObj.helperType = spec.helperType; }
+  if (spec.modeProps) { for (var prop$1 in spec.modeProps)
+    { modeObj[prop$1] = spec.modeProps[prop$1]; } }
 
-  return modeObj;
-};
+  return modeObj
+}
 
-exports.innerMode = function(mode, state) {
+// This can be used to attach properties to mode objects from
+// outside the actual mode definition.
+var modeExtensions = {};
+function extendMode(mode, properties) {
+  var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
+  copyObj(properties, exts);
+}
+
+function copyState(mode, state) {
+  if (state === true) { return state }
+  if (mode.copyState) { return mode.copyState(state) }
+  var nstate = {};
+  for (var n in state) {
+    var val = state[n];
+    if (val instanceof Array) { val = val.concat([]); }
+    nstate[n] = val;
+  }
+  return nstate
+}
+
+// Given a mode and a state (for that mode), find the inner mode and
+// state at the position that the state refers to.
+function innerMode(mode, state) {
   var info;
   while (mode.innerMode) {
     info = mode.innerMode(state);
-    if (!info || info.mode == mode) break;
+    if (!info || info.mode == mode) { break }
     state = info.state;
     mode = info.mode;
   }
-  return info || {mode: mode, state: state};
+  return info || {mode: mode, state: state}
 }
 
-exports.registerHelper = exports.registerGlobalHelper = Math.min;
+function startState(mode, a1, a2) {
+  return mode.startState ? mode.startState(a1, a2) : true
+}
 
-exports.runMode = function(string, modespec, callback, options) {
-  var mode = exports.getMode({indentUnit: 2}, modespec);
-  var lines = splitLines(string), state = (options && options.state) || exports.startState(mode);
-  var context = {lines: lines, line: 0}
-  for (var i = 0, e = lines.length; i < e; ++i, ++context.line) {
-    if (i) callback("\n");
-    var stream = new exports.StringStream(lines[i], 4, context);
-    if (!stream.string && mode.blankLine) mode.blankLine(state);
+var modeMethods = {
+  __proto__: null,
+  modes: modes,
+  mimeModes: mimeModes,
+  defineMode: defineMode,
+  defineMIME: defineMIME,
+  resolveMode: resolveMode,
+  getMode: getMode,
+  modeExtensions: modeExtensions,
+  extendMode: extendMode,
+  copyState: copyState,
+  innerMode: innerMode,
+  startState: startState
+};
+
+// Copy StringStream and mode methods into exports (CodeMirror) object.
+exports.StringStream = StringStream;
+exports.countColumn = countColumn;
+for (var exported in modeMethods) { exports[exported] = modeMethods[exported]; }
+
+// Shim library CodeMirror with the minimal CodeMirror defined above.
+require.cache[require.resolve("../../lib/codemirror")] = require.cache[require.resolve("./runmode.node")];
+require.cache[require.resolve("../../addon/runmode/runmode")] = require.cache[require.resolve("./runmode.node")];
+
+// Minimal default mode.
+exports.defineMode("null", function () { return ({token: function (stream) { return stream.skipToEnd(); }}); });
+exports.defineMIME("text/plain", "null");
+
+exports.registerHelper = exports.registerGlobalHelper = Math.min;
+exports.splitLines = function(string) { return string.split(/\r?\n|\r/) };
+
+exports.defaults = { indentUnit: 2 };
+
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: https://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    { mod(require("../../lib/codemirror")); }
+  else if (typeof define == "function" && define.amd) // AMD
+    { define(["../../lib/codemirror"], mod); }
+  else // Plain browser env
+    { mod(CodeMirror); }
+})(function(CodeMirror) {
+
+CodeMirror.runMode = function(string, modespec, callback, options) {
+  var mode = CodeMirror.getMode(CodeMirror.defaults, modespec);
+  var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize;
+
+  // Create a tokenizing callback function if passed-in callback is a DOM element.
+  if (callback.appendChild) {
+    var ie = /MSIE \d/.test(navigator.userAgent);
+    var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9);
+    var node = callback, col = 0;
+    node.innerHTML = "";
+    callback = function(text, style) {
+      if (text == "\n") {
+        // Emitting LF or CRLF on IE8 or earlier results in an incorrect display.
+        // Emitting a carriage return makes everything ok.
+        node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text));
+        col = 0;
+        return;
+      }
+      var content = "";
+      // replace tabs
+      for (var pos = 0;;) {
+        var idx = text.indexOf("\t", pos);
+        if (idx == -1) {
+          content += text.slice(pos);
+          col += text.length - pos;
+          break;
+        } else {
+          col += idx - pos;
+          content += text.slice(pos, idx);
+          var size = tabSize - col % tabSize;
+          col += size;
+          for (var i = 0; i < size; ++i) { content += " "; }
+          pos = idx + 1;
+        }
+      }
+      // Create a node with token style and append it to the callback DOM element.
+      if (style) {
+        var sp = node.appendChild(document.createElement("span"));
+        sp.className = "cm-" + style.replace(/ +/g, " cm-");
+        sp.appendChild(document.createTextNode(content));
+      } else {
+        node.appendChild(document.createTextNode(content));
+      }
+    };
+  }
+
+  var lines = CodeMirror.splitLines(string), state = (options && options.state) || CodeMirror.startState(mode);
+  for (var i = 0, e = lines.length; i < e; ++i) {
+    if (i) { callback("\n"); }
+    var stream = new CodeMirror.StringStream(lines[i], null, {
+      lookAhead: function(n) { return lines[i + n] },
+      baseToken: function() {}
+    });
+    if (!stream.string && mode.blankLine) { mode.blankLine(state); }
     while (!stream.eol()) {
       var style = mode.token(stream, state);
       callback(stream.current(), style, i, stream.start, state);
@@ -193,5 +326,4 @@ exports.runMode = function(string, modespec, callback, options) {
   }
 };
 
-require.cache[require.resolve("../../lib/codemirror")] = require.cache[require.resolve("./runmode.node")];
-require.cache[require.resolve("../../addon/runmode/runmode")] = require.cache[require.resolve("./runmode.node")];
+});
diff --git a/scripts/codemirror/addon/scroll/annotatescrollbar.js b/scripts/codemirror/addon/scroll/annotatescrollbar.js
index 3566258..c12e44c 100644
--- a/scripts/codemirror/addon/scroll/annotatescrollbar.js
+++ b/scripts/codemirror/addon/scroll/annotatescrollbar.js
@@ -43,7 +43,7 @@
     cm.on("markerAdded", this.resizeHandler);
     cm.on("markerCleared", this.resizeHandler);
     if (options.listenForChanges !== false)
-      cm.on("change", this.changeHandler = function() {
+      cm.on("changes", this.changeHandler = function() {
         scheduleRedraw(250);
       });
   }
@@ -72,10 +72,16 @@
     var wrapping = cm.getOption("lineWrapping");
     var singleLineH = wrapping && cm.defaultTextHeight() * 1.5;
     var curLine = null, curLineObj = null;
+
     function getY(pos, top) {
       if (curLine != pos.line) {
-        curLine = pos.line;
-        curLineObj = cm.getLineHandle(curLine);
+        curLine = pos.line
+        curLineObj = cm.getLineHandle(pos.line)
+        var visual = cm.getLineHandleVisualStart(curLineObj)
+        if (visual != curLineObj) {
+          curLine = cm.getLineNumber(visual)
+          curLineObj = visual
+        }
       }
       if ((curLineObj.widgets && curLineObj.widgets.length) ||
           (wrapping && curLineObj.height > singleLineH))
@@ -116,7 +122,7 @@
     this.cm.off("refresh", this.resizeHandler);
     this.cm.off("markerAdded", this.resizeHandler);
     this.cm.off("markerCleared", this.resizeHandler);
-    if (this.changeHandler) this.cm.off("change", this.changeHandler);
+    if (this.changeHandler) this.cm.off("changes", this.changeHandler);
     this.div.parentNode.removeChild(this.div);
   };
 });
diff --git a/scripts/codemirror/addon/search/match-highlighter.js b/scripts/codemirror/addon/search/match-highlighter.js
index b344ac7..3a4a7de 100644
--- a/scripts/codemirror/addon/search/match-highlighter.js
+++ b/scripts/codemirror/addon/search/match-highlighter.js
@@ -90,7 +90,9 @@
     var state = cm.state.matchHighlighter;
     cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style));
     if (state.options.annotateScrollbar && cm.showMatchesOnScrollbar) {
-      var searchFor = hasBoundary ? new RegExp("\\b" + query.replace(/[\\\[.+*?(){|^$]/g, "\\$&") + "\\b") : query;
+      var searchFor = hasBoundary ? new RegExp((/\w/.test(query.charAt(0)) ? "\\b" : "") +
+                                               query.replace(/[\\\[.+*?(){|^$]/g, "\\$&") +
+                                               (/\w/.test(query.charAt(query.length - 1)) ? "\\b" : "")) : query;
       state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, false,
         {className: "CodeMirror-selection-highlight-scrollbar"});
     }
diff --git a/scripts/codemirror/addon/search/searchcursor.js b/scripts/codemirror/addon/search/searchcursor.js
index aae36df..d586957 100644
--- a/scripts/codemirror/addon/search/searchcursor.js
+++ b/scripts/codemirror/addon/search/searchcursor.js
@@ -72,24 +72,26 @@
     }
   }
 
-  function lastMatchIn(string, regexp) {
-    var cutOff = 0, match
-    for (;;) {
-      regexp.lastIndex = cutOff
+  function lastMatchIn(string, regexp, endMargin) {
+    var match, from = 0
+    while (from <= string.length) {
+      regexp.lastIndex = from
       var newMatch = regexp.exec(string)
-      if (!newMatch) return match
-      match = newMatch
-      cutOff = match.index + (match[0].length || 1)
-      if (cutOff == string.length) return match
+      if (!newMatch) break
+      var end = newMatch.index + newMatch[0].length
+      if (end > string.length - endMargin) break
+      if (!match || end > match.index + match[0].length)
+        match = newMatch
+      from = newMatch.index + 1
     }
+    return match
   }
 
   function searchRegexpBackward(doc, regexp, start) {
     regexp = ensureFlags(regexp, "g")
     for (var line = start.line, ch = start.ch, first = doc.firstLine(); line >= first; line--, ch = -1) {
       var string = doc.getLine(line)
-      if (ch > -1) string = string.slice(0, ch)
-      var match = lastMatchIn(string, regexp)
+      var match = lastMatchIn(string, regexp, ch < 0 ? 0 : string.length - ch)
       if (match)
         return {from: Pos(line, match.index),
                 to: Pos(line, match.index + match[0].length),
@@ -98,16 +100,17 @@
   }
 
   function searchRegexpBackwardMultiline(doc, regexp, start) {
+    if (!maybeMultiline(regexp)) return searchRegexpBackward(doc, regexp, start)
     regexp = ensureFlags(regexp, "gm")
-    var string, chunk = 1
+    var string, chunkSize = 1, endMargin = doc.getLine(start.line).length - start.ch
     for (var line = start.line, first = doc.firstLine(); line >= first;) {
-      for (var i = 0; i < chunk; i++) {
+      for (var i = 0; i < chunkSize && line >= first; i++) {
         var curLine = doc.getLine(line--)
-        string = string == null ? curLine.slice(0, start.ch) : curLine + "\n" + string
+        string = string == null ? curLine : curLine + "\n" + string
       }
-      chunk *= 2
+      chunkSize *= 2
 
-      var match = lastMatchIn(string, regexp)
+      var match = lastMatchIn(string, regexp, endMargin)
       if (match) {
         var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n")
         var startLine = line + before.length, startCh = before[before.length - 1].length
@@ -237,7 +240,7 @@
       var result = this.matches(reverse, this.doc.clipPos(reverse ? this.pos.from : this.pos.to))
 
       // Implements weird auto-growing behavior on null-matches for
-      // backwards-compatiblity with the vim code (unfortunately)
+      // backwards-compatibility with the vim code (unfortunately)
       while (result && CodeMirror.cmpPos(result.from, result.to) == 0) {
         if (reverse) {
           if (result.from.ch) result.from = Pos(result.from.line, result.from.ch - 1)
diff --git a/scripts/codemirror/addon/tern/tern.js b/scripts/codemirror/addon/tern/tern.js
index 253309d..7be3681 100644
--- a/scripts/codemirror/addon/tern/tern.js
+++ b/scripts/codemirror/addon/tern/tern.js
@@ -231,7 +231,7 @@
         var content = ts.options.completionTip ? ts.options.completionTip(cur.data) : cur.data.doc;
         if (content) {
           tooltip = makeTooltip(node.parentNode.getBoundingClientRect().right + window.pageXOffset,
-                                node.getBoundingClientRect().top + window.pageYOffset, content);
+                                node.getBoundingClientRect().top + window.pageYOffset, content, cm);
           tooltip.className += " " + cls + "hint-doc";
         }
       });
@@ -334,7 +334,7 @@
     tip.appendChild(document.createTextNode(tp.rettype ? ") ->\u00a0" : ")"));
     if (tp.rettype) tip.appendChild(elt("span", cls + "type", tp.rettype));
     var place = cm.cursorCoords(null, "page");
-    var tooltip = ts.activeArgHints = makeTooltip(place.right + 1, place.bottom, tip)
+    var tooltip = ts.activeArgHints = makeTooltip(place.right + 1, place.bottom, tip, cm)
     setTimeout(function() {
       tooltip.clear = onEditorActivity(cm, function() {
         if (ts.activeArgHints == tooltip) closeArgHints(ts) })
@@ -601,7 +601,7 @@
   function tempTooltip(cm, content, ts) {
     if (cm.state.ternTooltip) remove(cm.state.ternTooltip);
     var where = cm.cursorCoords();
-    var tip = cm.state.ternTooltip = makeTooltip(where.right + 1, where.bottom, content);
+    var tip = cm.state.ternTooltip = makeTooltip(where.right + 1, where.bottom, content, cm);
     function maybeClear() {
       old = true;
       if (!mouseOnTip) clear();
@@ -637,11 +637,12 @@
     }
   }
 
-  function makeTooltip(x, y, content) {
+  function makeTooltip(x, y, content, cm) {
     var node = elt("div", cls + "tooltip", content);
     node.style.left = x + "px";
     node.style.top = y + "px";
-    document.body.appendChild(node);
+    var container = ((cm.options || {}).hintOptions || {}).container || document.body;
+    container.appendChild(node);
     return node;
   }
 
diff --git a/scripts/codemirror/addon/wrap/hardwrap.js b/scripts/codemirror/addon/wrap/hardwrap.js
index 29cc15f..f194946 100644
--- a/scripts/codemirror/addon/wrap/hardwrap.js
+++ b/scripts/codemirror/addon/wrap/hardwrap.js
@@ -29,11 +29,20 @@
     return {from: start, to: end};
   }
 
-  function findBreakPoint(text, column, wrapOn, killTrailingSpace) {
+  function findBreakPoint(text, column, wrapOn, killTrailingSpace, forceBreak) {
     var at = column
     while (at < text.length && text.charAt(at) == " ") at++
     for (; at > 0; --at)
       if (wrapOn.test(text.slice(at - 1, at + 1))) break;
+
+    if (at == 0 && !forceBreak) {
+      // didn't find a break point before column, in non-forceBreak mode try to
+      // find one after 'column'.
+      for (at = column + 1; at < text.length - 1; ++at) {
+        if (wrapOn.test(text.slice(at - 1, at + 1))) break;
+      }
+    }
+
     for (var first = true;; first = false) {
       var endOfText = at;
       if (killTrailingSpace)
@@ -47,6 +56,7 @@
     from = cm.clipPos(from); to = cm.clipPos(to);
     var column = options.column || 80;
     var wrapOn = options.wrapOn || /\s\S|-[^\.\d]/;
+    var forceBreak = options.forceBreak !== false;
     var killTrailing = options.killTrailingSpace !== false;
     var changes = [], curLine = "", curNo = from.line;
     var lines = cm.getRange(from, to, false);
@@ -68,7 +78,7 @@
       curLine += text;
       if (i) {
         var firstBreak = curLine.length > column && leadingSpace == spaceTrimmed &&
-          findBreakPoint(curLine, column, wrapOn, killTrailing);
+          findBreakPoint(curLine, column, wrapOn, killTrailing, forceBreak);
         // If this isn't broken, or is broken at a different point, remove old break
         if (!firstBreak || firstBreak.from != oldLen || firstBreak.to != oldLen + spaceInserted) {
           changes.push({text: [spaceInserted ? " " : ""],
@@ -80,12 +90,16 @@
         }
       }
       while (curLine.length > column) {
-        var bp = findBreakPoint(curLine, column, wrapOn, killTrailing);
-        changes.push({text: ["", leadingSpace],
-                      from: Pos(curNo, bp.from),
-                      to: Pos(curNo, bp.to)});
-        curLine = leadingSpace + curLine.slice(bp.to);
-        ++curNo;
+        var bp = findBreakPoint(curLine, column, wrapOn, killTrailing, forceBreak);
+        if (bp.from != bp.to || forceBreak) {
+          changes.push({text: ["", leadingSpace],
+                        from: Pos(curNo, bp.from),
+                        to: Pos(curNo, bp.to)});
+          curLine = leadingSpace + curLine.slice(bp.to);
+          ++curNo;
+        } else {
+          break;
+        }
       }
     }
     if (changes.length) cm.operation(function() {
diff --git a/scripts/codemirror/demo/folding.html b/scripts/codemirror/demo/folding.html
index b61ecee..166aa98 100644
--- a/scripts/codemirror/demo/folding.html
+++ b/scripts/codemirror/demo/folding.html
@@ -53,7 +53,23 @@
     
JavaScript:
HTML:
-
+ +
JSON with custom widget:
+
Python:

+ +

+
+    
+
+    

Running a CodeMirror mode outside of the editor. + The CodeMirror.runMode function, defined + in addon/runmode/runmode.js takes the following arguments:

+ +
+
text (string)
+
The document to run through the highlighter.
+
mode (mode spec)
+
The mode to use (must be loaded as normal).
+
output (function or DOM node)
+
If this is a function, it will be called for each token with + two arguments, the token's text and the token's style class (may + be null for unstyled tokens). If it is a DOM node, + the tokens will be converted to span elements as in + an editor, and inserted into the node + (through innerHTML).
+
+ + diff --git a/scripts/codemirror/demo/simplemode.html b/scripts/codemirror/demo/simplemode.html index 6b44a78..d7b0cfa 100644 --- a/scripts/codemirror/demo/simplemode.html +++ b/scripts/codemirror/demo/simplemode.html @@ -67,7 +67,8 @@ highlighted by the mode shown in it).

will be taken into account when matching the token. This regex has to capture groups when the token property is an array. If it captures groups, it must capture all of the string - (since JS provides no way to find out where a group matched). + (since JS provides no way to find out where a group matched). + Currently negative lookbehind assertion for regex is not supported, regardless of browser support.
token: string | array<string> | null
An optional token style. Multiple styles can be specified by separating them with dots or spaces. When this property holds an array of token styles, diff --git a/scripts/codemirror/demo/theme.html b/scripts/codemirror/demo/theme.html index 7bbc7a4..95d0f39 100644 --- a/scripts/codemirror/demo/theme.html +++ b/scripts/codemirror/demo/theme.html @@ -9,6 +9,8 @@ + + @@ -29,10 +31,14 @@ + + + + @@ -102,6 +108,8 @@ function findSequence(goal) { + + @@ -124,10 +132,14 @@ function findSequence(goal) { + + + + @@ -181,4 +193,4 @@ function findSequence(goal) { if (theme) { input.value = theme; selectTheme(); } }); - + diff --git a/scripts/codemirror/demo/vim.html b/scripts/codemirror/demo/vim.html index c939505..172ab6f 100644 --- a/scripts/codemirror/demo/vim.html +++ b/scripts/codemirror/demo/vim.html @@ -56,6 +56,7 @@ int getchar(void) }
Key buffer:
+
Vim mode:

The vim keybindings are enabled by including keymap/vim.js and setting the @@ -95,19 +96,22 @@ become a complete vim implementation

mode: "text/x-csrc", keyMap: "vim", matchBrackets: true, - showCursorWhenSelecting: true, - inputStyle: "contenteditable" + showCursorWhenSelecting: true }); var commandDisplay = document.getElementById('command-display'); var keys = ''; CodeMirror.on(editor, 'vim-keypress', function(key) { keys = keys + key; - commandDisplay.innerHTML = keys; + commandDisplay.innerText = keys; }); CodeMirror.on(editor, 'vim-command-done', function(e) { keys = ''; commandDisplay.innerHTML = keys; }); + var vimMode = document.getElementById('vim-mode'); + CodeMirror.on(editor, 'vim-mode-change', function(e) { + vimMode.innerText = JSON.stringify(e); + }); diff --git a/scripts/codemirror/doc/manual.html b/scripts/codemirror/doc/manual.html index 03e3a15..42ab549 100644 --- a/scripts/codemirror/doc/manual.html +++ b/scripts/codemirror/doc/manual.html @@ -58,6 +58,7 @@
  • Vim Mode API
  • @@ -69,7 +70,7 @@

    User manual and reference guide - version 5.48.2 + version 5.58.1

    CodeMirror is a code-editor component that can be embedded in @@ -78,9 +79,9 @@ functionality. It does provide a rich API on top of which such functionality can be straightforwardly implemented. See the addons included in the distribution, - and the list - of externally hosted addons, for reusable - implementations of extra features.

    + and 3rd party + packages on npm, for reusable implementations of extra + features.

    CodeMirror works with language-specific modes. Modes are JavaScript programs that help color (and optionally indent) text @@ -223,9 +224,10 @@ first mode that was loaded. It may be a string, which either simply names the mode or is a MIME type - associated with the mode. Alternatively, it may be an object - containing configuration options for the mode, with - a name property that names the mode (for + associated with the mode. The value "null" + indicates no highlighting should be applied. Alternatively, it + may be an object containing configuration options for the mode, + with a name property that names the mode (for example {name: "javascript", json: true}). The demo pages for each mode contain information about what configuration parameters the mode supports. You can ask CodeMirror which modes @@ -420,6 +422,10 @@ simply true), focusing of the editor is also disallowed.

    +
    screenReaderLabel: string
    +
    This label is read by the screenreaders when CodeMirror text area is focused. This + is helpful for accessibility.
    +
    showCursorWhenSelecting: boolean
    Whether the cursor should be drawn when a selection is active. Defaults to false.
    @@ -557,13 +563,13 @@ always rendered, and thus the browser's text search works on it. This will have bad effects on performance of big documents. - +
    spellcheck: boolean
    Specifies whether or not spellcheck will be enabled on the input.
    - +
    autocorrect: boolean
    Specifies whether or not autocorrect will be enabled on the input.
    - +
    autocapitalize: boolean
    Specifies whether or not autocapitalization will be enabled on the input.
    @@ -1880,6 +1886,9 @@ editor.setOption("extraKeys", { position (zero for the top, N to put it after the Nth other widget). Note that this only has effect once, when the widget is created. +
    className: string
    +
    Add an extra CSS class name to the wrapper element + created for the widget.
    Note that the widget node will become a descendant of nodes with CodeMirror-specific CSS classes, and those classes might in some @@ -2563,10 +2572,14 @@ editor.setOption("extraKeys", { and CodeMirror.fold.xml, for XML-style languages, and CodeMirror.fold.comment, for folding comment blocks. -
    widget: string|Element
    +
    widget: string | Element | fn(from: Pos, to: Pos) → string|Element
    The widget to show for folded ranges. Can be either a string, in which case it'll become a span with - class CodeMirror-foldmarker, or a DOM node.
    + class CodeMirror-foldmarker, or a DOM node. + To dynamically generate the widget, this can be a function + that returns a string or DOM node, which will then render + as described. The function will be invoked with parameters + identifying the range to be folded.
    scanUp: boolean
    When true (default is false), the addon will try to find foldable ranges on the lines above the current one if there @@ -2777,6 +2790,9 @@ editor.setOption("extraKeys", {
    Like customKeys above, but the bindings will be added to the set of default bindings, instead of replacing them.
    +
    scrollMargin: integer
    +
    Show this many lines before and after the selected item. + Default is 0.
    The following events will be fired on the completions object during completion: @@ -2903,6 +2919,7 @@ editor.setOption("extraKeys", { will only be executed when the promise resolves. By default, the linter will run (debounced) whenever the document is changed. You can pass a lintOnChange: false option to disable that. + You can pass a selfContain: true option to render the tooltip inside the editor instance. Depends on addon/lint/lint.css. A demo can be found here. @@ -2937,13 +2954,20 @@ editor.setOption("extraKeys", { see a demo here.
    mode/loadmode.js
    -
    Defines a CodeMirror.requireMode(modename, - callback) function that will try to load a given mode and - call the callback when it succeeded. You'll have to - set CodeMirror.modeURL to a string that mode paths - can be constructed from, for - example "mode/%N/%N.js"—the %N's will - be replaced with the mode name. Also +
    Defines a CodeMirror.requireMode(modename, callback, + options) function that will try to load a given mode and + call the callback when it succeeded. options is an + optional object that may contain: +
    +
    path: fn(modeName: string) → string
    +
    Defines the way mode names are mapped to paths.
    +
    loadMode: fn(path: string, cont: fn())
    +
    Override the way the mode script is loaded. By default, + this will use the CommonJS or AMD module loader if one is + present, and fall back to creating + a <script> tag otherwise.
    +
    + This addon also defines CodeMirror.autoLoadMode(instance, mode), which will ensure the given mode is loaded and cause the given editor instance to refresh its mode when the loading @@ -3114,10 +3138,20 @@ editor.setOption("extraKeys", {
    killTrailingSpace: boolean
    Whether trailing space caused by wrapping should be preserved, or deleted. Defaults to true.
    +
    forceBreak: boolean
    +
    If set to true forces a break at column in the case + when no wrapOn pattern is found in the range. If set to + false allows line to overflow the column limit if no + wrapOn pattern found. Defaults to true.
    A demo of the addon is available here. +
    scroll/scrollpastend.js
    +
    Defines an option `"scrollPastEnd"` that, when set to a + truthy value, allows the user to scroll one editor height of + empty space into view at the bottom of the editor.
    +
    merge/merge.js
    Implements an interface for merging changes, using either a 2-way or a 3-way view. The CodeMirror.MergeView @@ -3170,14 +3204,14 @@ editor.setOption("extraKeys", {
    tern/tern.js
    Provides integration with - the Tern JavaScript analysis + the Tern JavaScript analysis engine, for completion, definition finding, and minor refactoring help. See the demo for a very simple integration. For more involved scenarios, see the comments at the top of the addon and the implementation of the - (multi-file) demonstration + (multi-file) demonstration on the Tern website.
    @@ -3517,6 +3551,41 @@ editor.setOption("extraKeys", { extras.isEdit is applicable only to actions, determining whether it is recorded for replay for the . single-repeat command. + +
    unmap(lhs: string, ctx: string)
    +
    + Remove the command lhs if it is a user defined command. + If the command is an Ex to Ex or Ex to key mapping then the context + must be undefined or false. +
    + +
    mapclear(ctx: string)
    +
    + Remove all user-defined mappings for the provided context. +
    + +
    noremap(lhs: string, rhs: string, ctx: {string, array<string>})
    +
    + Non-recursive map function. This will not create mappings to key maps + that aren't present in the default key map. + If no context is provided then the mapping will be applied to each of + normal, insert, and visual mode. +
    + + +

    Events

    + +

    VIM mode signals a few events on the editor instance. For an example usage, see demo/vim.html#L101.

    + +
    +
    "vim-command-done" (reason: undefined)
    +
    Fired on keypress and mousedown where command has completed or no command found.
    + +
    "vim-keypress" (vimKey: string)
    +
    Fired on keypress, vimKey is in Vim's key notation.
    + +
    "vim-mode-change" (modeObj: object)
    +
    Fired after mode change, modeObj parameter is a {mode: string, ?subMode: string} object. Modes: "insert", "normal", "replace", "visual". Visual sub-modes: "linewise", "blockwise".

    Extending VIM

    @@ -3582,7 +3651,74 @@ editor.setOption("extraKeys", { command was prefixed with a line range, params.line and params.lineEnd will - be set. + be set. + +
    getRegisterController()
    +
    Returns the RegisterController that manages the state of registers + used by vim mode. For the RegisterController api see its + defintion here. +
    + +
    buildKeyMap()
    +
    + Not currently implemented. If you would like to contribute this please open + a pull request on Github. +
    + +
    defineRegister()
    +
    Defines an external register. The name should be a single character + that will be used to reference the register. The register should support + setText, pushText, clear, and toString. + See Register for a reference implementation. +
    + +
    getVimGlobalState_()
    +
    + Return a reference to the VimGlobalState. +
    + +
    resetVimGlobalState_()
    +
    + Reset the default values of the VimGlobalState to fresh values. Any options + set with setOption will also be applied to the reset global state. +
    + +
    maybeInitVimState_(cm: CodeMirror)
    +
    + Initialize cm.state.vim if it does not exist. Returns cm.state.vim. +
    + +
    handleKey(cm: CodeMirror, key: string, origin: string)
    +
    + Convenience function to pass the arguments to findKey and + call returned function if it is defined. +
    + +
    findKey(cm: CodeMirror, key: string, origin: string)
    +
    + This is the outermost function called by CodeMirror, after keys have + been mapped to their Vim equivalents. Finds a command based on the key + (and cached keys if there is a multi-key sequence). Returns undefined + if no key is matched, a noop function if a partial match is found (multi-key), + and a function to execute the bound command if a a key is matched. The + function always returns true. +
    + +
    suppressErrorLogging: boolean
    +
    Whether to use suppress the use of console.log when catching an + error in the function returned by findKey. + Defaults to false.
    + +
    exitVisualMode(cm: CodeMirror, ?moveHead: boolean)
    +
    Exit visual mode. If moveHead is set to false, the CodeMirror selection + will not be touched. The caller assumes the responsibility of putting + the cursor in the right place. +
    + +
    exitInsertMode(cm: CodeMirror)
    +
    + Exit insert mode. +
    diff --git a/scripts/codemirror/doc/realworld.html b/scripts/codemirror/doc/realworld.html index fdb278d..da61825 100644 --- a/scripts/codemirror/doc/realworld.html +++ b/scripts/codemirror/doc/realworld.html @@ -25,7 +25,9 @@ request if you'd like your project to be added to this list.

      +
    • Adaface PairPro (Shared code editor with compiler and video conferencing)
    • Adobe Brackets (code editor)
    • +
    • Adnuntius (used for in-browser code editing and version history)
    • ALM Tools (TypeScript powered IDE)
    • Amber (JavaScript-based Smalltalk system)
    • APEye (tool for testing & documenting APIs)
    • @@ -39,6 +41,7 @@
    • Cargo Collective (creative publishing platform)
    • Chrome DevTools
    • ClickHelp (technical writing tool)
    • +
    • Clone-It (HTML & CSS learning game)
    • Colon (A flexible text editor or IDE)
    • CodeWorld (Haskell playground)
    • Complete.ly playground
    • @@ -49,6 +52,7 @@
    • CodeFights (practice programming)
    • CodeMirror Eclipse (embed CM in Eclipse)
    • CodeMirror movie (scripted editing demos)
    • +
    • CodeMirror Record (codemirror activity recording and playback)
    • CodeMirror2-GWT (Google Web Toolkit wrapper)
    • Code Monster & Code Maven (learning environment)
    • Codepen (gallery of animations)
    • @@ -57,7 +61,6 @@
    • Code School (online tech learning environment)
    • Code Snippets (WordPress snippet management plugin)
    • Code together (collaborative editing)
    • -
    • Codev (collaborative IDE)
    • Codevolve (programming lessons as-a-service)
    • CodeZample (code snippet sharing)
    • Codio (Web IDE)
    • @@ -101,6 +104,8 @@
    • Histone template engine playground
    • Homegenie (home automation server)
    • ICEcoder (web IDE)
    • +
    • Innovay Web Tools (HTML, JS, CSS code beautifier)
    • +
    • Intervue (Pair programming for interviews)
    • IPython (interactive computing shell)
    • iTrading (Algorithmic Trading)
    • i-MOS (modeling and simulation platform)
    • @@ -150,6 +155,7 @@
    • RealTime.io (Internet-of-Things infrastructure)
    • Refork (animation demo gallery and sharing)
    • SageMathCell (interactive mathematical software)
    • +
    • SASS2CSS (SASS, SCSS or LESS to CSS converter and CSS beautifier)
    • SageMathCloud (interactive mathematical software environment)
    • salvare (real-time collaborative code editor)
    • ServePHP (PHP code testing in Chrome dev tools)
    • @@ -171,11 +177,13 @@
    • The File Tree (collab editor)
    • TileMill (map design tool)
    • Tiki (wiki CMS groupware)
    • +
    • Tistory (blog service)
    • Toolsverse Data Explorer (database management)
    • Tumblr code highlighting shim
    • TurboPY (web publishing framework)
    • UmpleOnline (model-oriented programming tool)
    • Upsource (code browser and review tool)
    • +
    • Violentmonkey (userscript manager / editor)
    • Waliki (wiki engine)
    • Wamer (web application builder)
    • webappfind (windows file bindings for webapps)
    • diff --git a/scripts/codemirror/doc/releases.html b/scripts/codemirror/doc/releases.html index 11d9430..3b4378f 100644 --- a/scripts/codemirror/doc/releases.html +++ b/scripts/codemirror/doc/releases.html @@ -30,6 +30,178 @@

      Version 5.x

      +

      21-09-2020: Version 5.58.0:

      + + + +

      Version 5.x

      + +

      21-09-2020: Version 5.58.0:

      + +
        +
      • Make backspace delete by code point, not glyph.
      • +
      • Suppress flickering focus outline when clicking on scrollbars in Chrome.
      • +
      • Fix a bug that prevented attributes added via markText from showing up unless the span also had some other styling.
      • +
      • Suppress cut and paste context menu entries in readonly editors in Chrome.
      • +
      • placeholder addon: Update placeholder visibility during composition.
      • +
      • Make it less cumbersome to style new lint message types.
      • +
      • vim bindings: Support black hole register, gn and gN
      • +
      + +

      20-08-2020: Version 5.57.0:

      + +
        +
      • Fix issue that broke binding the macOS Command key.
      • +
      • comment addon: Keep selection in front of inserted markers when adding a block comment.
      • +
      • css mode: Recognize more properties and value names.
      • +
      • annotatescrollbar addon: Don’t hide matches in collapsed content.
      • +
      • vim bindings: Support tag text objects in xml and html modes.
      • +
      + +

      20-07-2020: Version 5.56.0:

      + +
        +
      • Line-wise pasting was fixed on Chrome Windows.
      • +
      • wast mode: Follow standard changes.
      • +
      • soy mode: Support import expressions, template type, and loop indices.
      • +
      • sql-hint addon: Improve handling of double quotes.
      • +
      • New features

      • +
      • show-hint addon: New option scrollMargin to control how many options are visible beyond the selected one.
      • +
      • hardwrap addon: New option forceBreak to disable breaking of words that are longer than a line.
      • +
      + +

      21-06-2020: Version 5.55.0:

      + +
        +
      • The editor no longer overrides the rendering of zero-width joiners (allowing combined emoji to be shown).
      • +
      • vim bindings: Fix an issue where the vim-mode-change event was fired twice.
      • +
      • javascript mode: Only allow -->-style comments at the start of a line.
      • +
      • julia mode: Improve indentation.
      • +
      • pascal mode: Recognize curly bracket comments.
      • +
      • runmode addon: Further sync up the implementation of the standalone and node variants with the regular library.
      • +
      • New features

      • +
      • loadmode addon: Allow overriding the way the addon constructs filenames and loads modules.
      • +
      + +

      20-05-2020: Version 5.54.0:

      + +
        +
      • runmode addon: Properly support for cross-line lookahead.
      • +
      • vim bindings: Allow Ex-Commands with non-word names.
      • +
      • gfm mode: Add a fencedCodeBlockDefaultMode option.
      • +
      • Improve support for having focus inside in-editor widgets in contenteditable-mode.
      • +
      • Fix issue where the scroll position could jump when clicking on a selection in Chrome.
      • +
      • python mode: Better format string support.
      • +
      • javascript mode: Improve parsing of private properties and class fields.
      • +
      • matchbrackets addon: Disable highlighting when the editor doesn’t have focus.
      • +
      + +

      21-04-2020: Version 5.53.2:

      + + + +

      21-04-2020: Version 5.53.0:

      + +
        +
      • New option: screenReaderLabel to add a label to the editor.
      • +
      • New mode: wast.
      • +
      • Fix a bug where the editor layout could remain confused after a call to refresh when line wrapping was enabled.
      • +
      • dialog addon: Don’t close dialogs when the document window loses focus.
      • +
      • merge addon: Compensate for editor top position when aligning lines.
      • +
      • vim bindings: Improve EOL handling.
      • +
      • emacs bindings: Include default keymap as a fallback.
      • +
      • julia mode: Fix an infinite loop bug.
      • +
      • show-hint addon: Scroll cursor into view when picking a completion.
      • +
      + +

      20-03-2020: Version 5.52.2:

      + +
        +
      • Fix selection management in contenteditable mode when the editor doesn’t have focus.
      • +
      • Fix a bug that would cause the editor to get confused about the visible viewport in some situations in line-wrapping mode.
      • +
      • markdown mode: Don’t treat single dashes as setext header markers.
      • +
      • zenburn theme: Make sure background styles take precedence over default styles.
      • +
      • css mode: Recognize a number of new properties.
      • +
      + +

      20-02-2020: Version 5.52.0:

      + +
        +
      • Fix a bug in handling of bidi text with Arabic numbers in a right-to-left editor.
      • +
      • Fix a crash when combining file drop with a "beforeChange" filter.
      • +
      • Prevent issue when passing negative coordinates to scrollTo.
      • +
      • lint and tern addons: Allow the tooltip to be appended to the editor wrapper element instead of the document body.
      • +
      + +

      20-01-2020: Version 5.51.0:

      + +
        +
      • Fix the behavior of the home and end keys when direction is set to "rtl".
      • +
      • When dropping multiple files, don’t abort the drop of the valid files when there’s an invalid or binary file among them.
      • +
      • Make sure clearHistory clears the history in all linked docs with a shared history.
      • +
      • vim bindings: Fix behavior of ' and ` marks, fix R in visual mode.
      • +
      • vim bindings: Support gi, gI, and gJ.
      • +
      + +

      01-01-2020: Version 5.50.2:

      + +
        +
      • Fix bug that broke removal of line widgets.
      • +
      + +

      20-12-2019: Version 5.50.0:

      + + + +

      21-10-2019: Version 5.49.2:

      + + + +

      20-09-2019: Version 5.49.0:

      + + + +

      20-08-2019: Version 5.48.4:

      + +
        +
      • Make default styles for line elements more specific so that they don’t apply to all <pre> elements inside the editor.
      • +
      • Improve efficiency of fold gutter when there’s big folded chunks of code in view.
      • +
      • Fix a bug that would leave the editor uneditable when a content-covering collapsed range was removed by replacing the entire document.
      • +
      • julia mode: Support number separators.
      • +
      • asterisk mode: Improve comment support.
      • +
      • handlebars mode: Support triple-brace tags.
      • +
      +

      20-07-2019: Version 5.48.2:

        diff --git a/scripts/codemirror/index.html b/scripts/codemirror/index.html index 90c429b..ff27b92 100644 --- a/scripts/codemirror/index.html +++ b/scripts/codemirror/index.html @@ -99,7 +99,7 @@
    - Get the current version: 5.48.2.
    + Get the current version: 5.58.1.
    You can see the code,
    read the release notes,
    or study the user manual. @@ -171,11 +171,6 @@ that explicit, we have a code of conduct that applies to communication around the project.

    - -

    A list of CodeMirror-related software that is not part of the - main distribution is maintained - on our - wiki. Feel free to add your project.

    @@ -195,4 +190,21 @@ pretty well.

    +
    + + +

    Sponsors

    +

    These companies support development of this project:

    + +
    + diff --git a/scripts/codemirror/keymap/emacs.js b/scripts/codemirror/keymap/emacs.js index fe62d44..fe4882e 100644 --- a/scripts/codemirror/keymap/emacs.js +++ b/scripts/codemirror/keymap/emacs.js @@ -404,7 +404,8 @@ "Ctrl-X H": "selectAll", "Ctrl-Q Tab": repeated("insertTab"), - "Ctrl-U": addPrefixMap + "Ctrl-U": addPrefixMap, + "fallthrough": "default" }); var prefixMap = {"Ctrl-G": clearPrefix}; diff --git a/scripts/codemirror/keymap/sublime.js b/scripts/codemirror/keymap/sublime.js index 799641a..7edf172 100644 --- a/scripts/codemirror/keymap/sublime.js +++ b/scripts/codemirror/keymap/sublime.js @@ -22,17 +22,21 @@ if (dir < 0 && start.ch == 0) return doc.clipPos(Pos(start.line - 1)); var line = doc.getLine(start.line); if (dir > 0 && start.ch >= line.length) return doc.clipPos(Pos(start.line + 1, 0)); - var state = "start", type; - for (var pos = start.ch, e = dir < 0 ? 0 : line.length, i = 0; pos != e; pos += dir, i++) { + var state = "start", type, startPos = start.ch; + for (var pos = startPos, e = dir < 0 ? 0 : line.length, i = 0; pos != e; pos += dir, i++) { var next = line.charAt(dir < 0 ? pos - 1 : pos); var cat = next != "_" && CodeMirror.isWordChar(next) ? "w" : "o"; if (cat == "w" && next.toUpperCase() == next) cat = "W"; if (state == "start") { if (cat != "o") { state = "in"; type = cat; } + else startPos = pos + dir } else if (state == "in") { if (type != cat) { if (type == "w" && cat == "W" && dir < 0) pos--; - if (type == "W" && cat == "w" && dir > 0) { type = "w"; continue; } + if (type == "W" && cat == "w" && dir > 0) { // From uppercase to lowercase + if (pos == startPos + 1) { type = "w"; continue; } + else pos--; + } break; } } @@ -144,14 +148,24 @@ cur = cm.getSearchCursor(query, Pos(cm.firstLine(), 0)); found = cur.findNext(); } - if (!found || isSelectedRange(cm.listSelections(), cur.from(), cur.to())) - return CodeMirror.Pass + if (!found || isSelectedRange(cm.listSelections(), cur.from(), cur.to())) return cm.addSelection(cur.from(), cur.to()); } if (fullWord) cm.state.sublimeFindFullWord = cm.doc.sel; }; + cmds.skipAndSelectNextOccurrence = function(cm) { + var prevAnchor = cm.getCursor("anchor"), prevHead = cm.getCursor("head"); + cmds.selectNextOccurrence(cm); + if (CodeMirror.cmpPos(prevAnchor, prevHead) != 0) { + cm.doc.setSelections(cm.doc.listSelections() + .filter(function (sel) { + return sel.anchor != prevAnchor || sel.head != prevHead; + })); + } + } + function addCursorToSelection(cm, dir) { var ranges = cm.listSelections(), newRanges = []; for (var i = 0; i < ranges.length; i++) { @@ -175,7 +189,8 @@ function isSelectedRange(ranges, from, to) { for (var i = 0; i < ranges.length; i++) - if (ranges[i].from() == from && ranges[i].to() == to) return true + if (CodeMirror.cmpPos(ranges[i].from(), from) == 0 && + CodeMirror.cmpPos(ranges[i].to(), to) == 0) return true return false } @@ -213,11 +228,15 @@ if (!selectBetweenBrackets(cm)) return CodeMirror.Pass; }; + function puncType(type) { + return !type ? null : /\bpunctuation\b/.test(type) ? type : undefined + } + cmds.goToBracket = function(cm) { cm.extendSelectionsBy(function(range) { - var next = cm.scanForBracket(range.head, 1); + var next = cm.scanForBracket(range.head, 1, puncType(cm.getTokenTypeAt(range.head))); if (next && CodeMirror.cmpPos(next.pos, range.head) != 0) return next.pos; - var prev = cm.scanForBracket(range.head, -1); + var prev = cm.scanForBracket(range.head, -1, puncType(cm.getTokenTypeAt(Pos(range.head.line, range.head.ch + 1)))); return prev && Pos(prev.pos.line, prev.pos.ch + 1) || range.head; }); }; @@ -597,6 +616,7 @@ "Shift-Cmd-F2": "clearBookmarks", "Alt-F2": "selectBookmarks", "Backspace": "smartBackspace", + "Cmd-K Cmd-D": "skipAndSelectNextOccurrence", "Cmd-K Cmd-K": "delLineRight", "Cmd-K Cmd-U": "upcaseAtCursor", "Cmd-K Cmd-L": "downcaseAtCursor", @@ -608,6 +628,7 @@ "Cmd-K Cmd-C": "showInCenter", "Cmd-K Cmd-G": "clearBookmarks", "Cmd-K Cmd-Backspace": "delLineLeft", + "Cmd-K Cmd-1": "foldAll", "Cmd-K Cmd-0": "unfoldAll", "Cmd-K Cmd-J": "unfoldAll", "Ctrl-Shift-Up": "addCursorToPrevLine", @@ -657,6 +678,7 @@ "Shift-Ctrl-F2": "clearBookmarks", "Alt-F2": "selectBookmarks", "Backspace": "smartBackspace", + "Ctrl-K Ctrl-D": "skipAndSelectNextOccurrence", "Ctrl-K Ctrl-K": "delLineRight", "Ctrl-K Ctrl-U": "upcaseAtCursor", "Ctrl-K Ctrl-L": "downcaseAtCursor", @@ -668,6 +690,7 @@ "Ctrl-K Ctrl-C": "showInCenter", "Ctrl-K Ctrl-G": "clearBookmarks", "Ctrl-K Ctrl-Backspace": "delLineLeft", + "Ctrl-K Ctrl-1": "foldAll", "Ctrl-K Ctrl-0": "unfoldAll", "Ctrl-K Ctrl-J": "unfoldAll", "Ctrl-Alt-Up": "addCursorToPrevLine", diff --git a/scripts/codemirror/keymap/vim.js b/scripts/codemirror/keymap/vim.js index 95b19b2..789e1e5 100644 --- a/scripts/codemirror/keymap/vim.js +++ b/scripts/codemirror/keymap/vim.js @@ -8,7 +8,7 @@ * Supported Ex commands: * Refer to defaultExCommandMap below. * - * Registers: unnamed, -, a-z, A-Z, 0-9 + * Registers: unnamed, -, ., :, /, _, a-z, A-Z, 0-9 * (Does not respect the special case for number registers when delete * operator is made with these commands: %, (, ), , /, ?, n, N, {, } ) * TODO: Implement the remaining registers. @@ -141,6 +141,8 @@ { keys: 'gU', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: false}, isEdit: true }, { keys: 'n', type: 'motion', motion: 'findNext', motionArgs: { forward: true, toJumplist: true }}, { keys: 'N', type: 'motion', motion: 'findNext', motionArgs: { forward: false, toJumplist: true }}, + { keys: 'gn', type: 'motion', motion: 'findAndSelectNextInclusive', motionArgs: { forward: true }}, + { keys: 'gN', type: 'motion', motion: 'findAndSelectNextInclusive', motionArgs: { forward: false }}, // Operator-Motion dual commands { keys: 'x', type: 'operatorMotion', operator: 'delete', motion: 'moveByCharacters', motionArgs: { forward: true }, operatorMotionArgs: { visualLine: false }}, { keys: 'X', type: 'operatorMotion', operator: 'delete', motion: 'moveByCharacters', motionArgs: { forward: false }, operatorMotionArgs: { visualLine: true }}, @@ -164,7 +166,9 @@ { keys: 'A', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'eol' }, context: 'normal' }, { keys: 'A', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'endOfSelectedArea' }, context: 'visual' }, { keys: 'i', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'inplace' }, context: 'normal' }, + { keys: 'gi', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'lastEdit' }, context: 'normal' }, { keys: 'I', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'firstNonBlank'}, context: 'normal' }, + { keys: 'gI', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'bol'}, context: 'normal' }, { keys: 'I', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'startOfSelectedArea' }, context: 'visual' }, { keys: 'o', type: 'action', action: 'newLineAndEnterInsertMode', isEdit: true, interlaceInsertRepeat: true, actionArgs: { after: true }, context: 'normal' }, { keys: 'O', type: 'action', action: 'newLineAndEnterInsertMode', isEdit: true, interlaceInsertRepeat: true, actionArgs: { after: false }, context: 'normal' }, @@ -174,13 +178,15 @@ { keys: '', type: 'action', action: 'toggleVisualMode', actionArgs: { blockwise: true }}, { keys: 'gv', type: 'action', action: 'reselectLastSelection' }, { keys: 'J', type: 'action', action: 'joinLines', isEdit: true }, + { keys: 'gJ', type: 'action', action: 'joinLines', actionArgs: { keepSpaces: true }, isEdit: true }, { keys: 'p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: true, isEdit: true }}, { keys: 'P', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: false, isEdit: true }}, { keys: 'r', type: 'action', action: 'replace', isEdit: true }, { keys: '@', type: 'action', action: 'replayMacro' }, { keys: 'q', type: 'action', action: 'enterMacroRecordMode' }, // Handle Replace-mode as a special case of insert mode. - { keys: 'R', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { replace: true }}, + { keys: 'R', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { replace: true }, context: 'normal'}, + { keys: 'R', type: 'operator', operator: 'change', operatorArgs: { linewise: true, fullLine: true }, context: 'visual', exitVisualBlock: true}, { keys: 'u', type: 'action', action: 'undo', context: 'normal' }, { keys: 'u', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: true}, context: 'visual', isEdit: true }, { keys: 'U', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: false}, context: 'visual', isEdit: true }, @@ -230,7 +236,6 @@ { name: 'undo', shortName: 'u' }, { name: 'redo', shortName: 'red' }, { name: 'set', shortName: 'se' }, - { name: 'set', shortName: 'se' }, { name: 'setlocal', shortName: 'setl' }, { name: 'setglobal', shortName: 'setg' }, { name: 'sort', shortName: 'sor' }, @@ -291,16 +296,16 @@ clearFatCursorMark(cm); var ranges = cm.listSelections(), result = [] for (var i = 0; i < ranges.length; i++) { - var range = ranges[i] + var range = ranges[i]; if (range.empty()) { - if (range.anchor.ch < cm.getLine(range.anchor.line).length) { + var lineLength = cm.getLine(range.anchor.line).length; + if (range.anchor.ch < lineLength) { result.push(cm.markText(range.anchor, Pos(range.anchor.line, range.anchor.ch + 1), - {className: "cm-fat-cursor-mark"})) + {className: "cm-fat-cursor-mark"})); } else { - var widget = document.createElement("span") - widget.textContent = "\u00a0" - widget.className = "cm-fat-cursor-mark" - result.push(cm.setBookmark(range.anchor, {widget: widget})) + result.push(cm.markText(Pos(range.anchor.line, lineLength - 1), + Pos(range.anchor.line, lineLength), + {className: "cm-fat-cursor-mark"})); } } } @@ -413,7 +418,7 @@ var lowerCaseAlphabet = makeKeyRange(97, 26); var numbers = makeKeyRange(48, 10); var validMarks = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['<', '>']); - var validRegisters = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['-', '"', '.', ':', '/']); + var validRegisters = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['-', '"', '.', ':', '_', '/']); function isLine(cm, line) { return line >= cm.firstLine() && line <= cm.lastLine(); @@ -594,9 +599,16 @@ } return mark; } + function find(cm, offset) { + var oldPointer = pointer; + var mark = move(cm, offset); + pointer = oldPointer; + return mark && mark.find(); + } return { cachedCursor: undefined, //used for # and * jumps add: add, + find: find, move: move }; }; @@ -1118,6 +1130,8 @@ } RegisterController.prototype = { pushText: function(registerName, operator, text, linewise, blockwise) { + // The black hole register, "_, means delete/yank to nowhere. + if (registerName === '_') return; if (linewise && text.charAt(text.length - 1) !== '\n'){ text += '\n'; } @@ -1293,6 +1307,10 @@ } inputState.operator = command.operator; inputState.operatorArgs = copyArgs(command.operatorArgs); + if (command.exitVisualBlock) { + vim.visualBlock = false; + updateCmSelection(cm); + } if (vim.visualMode) { // Operating on a selection in visual mode. We don't need a motion. this.evalInput(cm, vim); @@ -1560,7 +1578,7 @@ motionArgs.repeat = repeat; clearInputState(cm); if (motion) { - var motionResult = motions[motion](cm, origHead, motionArgs, vim); + var motionResult = motions[motion](cm, origHead, motionArgs, vim, inputState); vim.lastMotion = motions[motion]; if (!motionResult) { return; @@ -1588,10 +1606,10 @@ } if (vim.visualMode) { if (!(vim.visualBlock && newHead.ch === Infinity)) { - newHead = clipCursorToContent(cm, newHead, vim.visualBlock); + newHead = clipCursorToContent(cm, newHead); } if (newAnchor) { - newAnchor = clipCursorToContent(cm, newAnchor, true); + newAnchor = clipCursorToContent(cm, newAnchor); } newAnchor = newAnchor || oldAnchor; sel.anchor = newAnchor; @@ -1758,6 +1776,87 @@ highlightSearchMatches(cm, query); return findNext(cm, prev/** prev */, query, motionArgs.repeat); }, + /** + * Find and select the next occurrence of the search query. If the cursor is currently + * within a match, then find and select the current match. Otherwise, find the next occurrence in the + * appropriate direction. + * + * This differs from `findNext` in the following ways: + * + * 1. Instead of only returning the "from", this returns a "from", "to" range. + * 2. If the cursor is currently inside a search match, this selects the current match + * instead of the next match. + * 3. If there is no associated operator, this will turn on visual mode. + */ + findAndSelectNextInclusive: function(cm, _head, motionArgs, vim, prevInputState) { + var state = getSearchState(cm); + var query = state.getQuery(); + + if (!query) { + return; + } + + var prev = !motionArgs.forward; + prev = (state.isReversed()) ? !prev : prev; + + // next: [from, to] | null + var next = findNextFromAndToInclusive(cm, prev, query, motionArgs.repeat, vim); + + // No matches. + if (!next) { + return; + } + + // If there's an operator that will be executed, return the selection. + if (prevInputState.operator) { + return next; + } + + // At this point, we know that there is no accompanying operator -- let's + // deal with visual mode in order to select an appropriate match. + + var from = next[0]; + // For whatever reason, when we use the "to" as returned by searchcursor.js directly, + // the resulting selection is extended by 1 char. Let's shrink it so that only the + // match is selected. + var to = Pos(next[1].line, next[1].ch - 1); + + if (vim.visualMode) { + // If we were in visualLine or visualBlock mode, get out of it. + if (vim.visualLine || vim.visualBlock) { + vim.visualLine = false; + vim.visualBlock = false; + CodeMirror.signal(cm, "vim-mode-change", {mode: "visual", subMode: ""}); + } + + // If we're currently in visual mode, we should extend the selection to include + // the search result. + var anchor = vim.sel.anchor; + if (anchor) { + if (state.isReversed()) { + if (motionArgs.forward) { + return [anchor, from]; + } + + return [anchor, to]; + } else { + if (motionArgs.forward) { + return [anchor, to]; + } + + return [anchor, from]; + } + } + } else { + // Let's turn visual mode on. + vim.visualMode = true; + vim.visualLine = false; + vim.visualBlock = false; + CodeMirror.signal(cm, "vim-mode-change", {mode: "visual", subMode: ""}); + } + + return prev ? [to, from] : [from, to]; + }, goToMark: function(cm, _head, motionArgs, vim) { var pos = getMarkPos(cm, vim, motionArgs.selectedCharacter); if (pos) { @@ -1843,12 +1942,18 @@ var line = motionArgs.forward ? cur.line + repeat : cur.line - repeat; var first = cm.firstLine(); var last = cm.lastLine(); + var posV = cm.findPosV(cur, (motionArgs.forward ? repeat : -repeat), 'line', vim.lastHSPos); + var hasMarkedText = motionArgs.forward ? posV.line > line : posV.line < line; + if (hasMarkedText) { + line = posV.line; + endCh = posV.ch; + } // Vim go to line begin or line end when cursor at first/last line and // move to previous/next line is triggered. if (line < first && cur.line == first){ return this.moveToStartOfLine(cm, head, motionArgs, vim); - }else if (line > last && cur.line == last){ - return this.moveToEol(cm, head, motionArgs, vim, true); + } else if (line > last && cur.line == last){ + return moveToEol(cm, head, motionArgs, vim, true); } if (motionArgs.toFirstChar){ endCh=findFirstNonWhiteSpaceCharacter(cm.getLine(line)); @@ -1950,16 +2055,8 @@ vim.lastHSPos = cm.charCoords(head,'div').left; return moveToColumn(cm, repeat); }, - moveToEol: function(cm, head, motionArgs, vim, keepHPos) { - var cur = head; - var retval= Pos(cur.line + motionArgs.repeat - 1, Infinity); - var end=cm.clipPos(retval); - end.ch--; - if (!keepHPos) { - vim.lastHPos = Infinity; - vim.lastHSPos = cm.charCoords(end,'div').left; - } - return retval; + moveToEol: function(cm, head, motionArgs, vim) { + return moveToEol(cm, head, motionArgs, vim, false); }, moveToFirstNonWhiteSpaceCharacter: function(cm, head) { // Go to the start of the line where the text begins, or the end for @@ -2049,6 +2146,8 @@ if (operatorArgs) { operatorArgs.linewise = true; } tmp.end.line--; } + } else if (character === 't') { + tmp = expandTagUnderCursor(cm, head, inclusive); } else { // No text object defined for this, don't move. return null; @@ -2098,9 +2197,9 @@ change: function(cm, args, ranges) { var finalHead, text; var vim = cm.state.vim; + var anchor = ranges[0].anchor, + head = ranges[0].head; if (!vim.visualMode) { - var anchor = ranges[0].anchor, - head = ranges[0].head; text = cm.getRange(anchor, head); var lastState = vim.lastEditInputState || {}; if (lastState.motion == "moveByWords" && !isWhiteSpaceString(text)) { @@ -2128,6 +2227,13 @@ anchor.ch = Number.MAX_VALUE; } finalHead = anchor; + } else if (args.fullLine) { + head.ch = Number.MAX_VALUE; + head.line--; + cm.setSelection(anchor, head) + text = cm.getSelection(); + cm.replaceSelection(""); + finalHead = anchor; } else { text = cm.getSelection(); var replacement = fillArray('', ranges.length); @@ -2172,8 +2278,7 @@ vimGlobalState.registerController.pushText( args.registerName, 'delete', text, args.linewise, vim.visualBlock); - var includeLineBreak = vim.insertMode - return clipCursorToContent(cm, finalHead, includeLineBreak); + return clipCursorToContent(cm, finalHead); }, indent: function(cm, args, ranges) { var vim = cm.state.vim; @@ -2355,6 +2460,8 @@ var height = cm.listSelections().length; if (insertAt == 'eol') { head = Pos(head.line, lineLength(cm, head.line)); + } else if (insertAt == 'bol') { + head = Pos(head.line, 0); } else if (insertAt == 'charAfter') { head = offsetCursor(head, 0, 1); } else if (insertAt == 'firstNonBlank') { @@ -2393,6 +2500,8 @@ if (vim.visualMode){ return; } + } else if (insertAt == 'lastEdit') { + head = getLastEditPos(cm) || head; } cm.setOption('disableInput', false); if (actionArgs && actionArgs.replace) { @@ -2428,8 +2537,7 @@ vim.visualLine = !!actionArgs.linewise; vim.visualBlock = !!actionArgs.blockwise; head = clipCursorToContent( - cm, Pos(anchor.line, anchor.ch + repeat - 1), - true /** includeLineBreak */); + cm, Pos(anchor.line, anchor.ch + repeat - 1)); vim.sel = { anchor: anchor, head: head @@ -2501,7 +2609,9 @@ var tmp = Pos(curStart.line + 1, lineLength(cm, curStart.line + 1)); var text = cm.getRange(curStart, tmp); - text = text.replace(/\n\s*/g, ' '); + text = actionArgs.keepSpaces + ? text.replace(/\n\r?/g, '') + : text.replace(/\n\s*/g, ' '); cm.replaceRange(text, curStart, tmp); } var curFinalPos = Pos(curStart.line, finalCh); @@ -2803,10 +2913,11 @@ * Clips cursor to ensure that line is within the buffer's range * If includeLineBreak is true, then allow cur.ch == lineLength. */ - function clipCursorToContent(cm, cur, includeLineBreak) { + function clipCursorToContent(cm, cur) { + var vim = cm.state.vim; + var includeLineBreak = vim.insertMode || vim.visualMode; var line = Math.min(Math.max(cm.firstLine(), cur.line), cm.lastLine() ); - var maxCh = lineLength(cm, line) - 1; - maxCh = (includeLineBreak) ? maxCh + 1 : maxCh; + var maxCh = lineLength(cm, line) - 1 + !!includeLineBreak; var ch = Math.min(Math.max(0, cur.ch), maxCh); return Pos(line, ch); } @@ -3171,10 +3282,8 @@ vim.visualMode = false; vim.visualLine = false; vim.visualBlock = false; - CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"}); - if (vim.fakeCursor) { - vim.fakeCursor.clear(); - } + if (!vim.insertMode) CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"}); + clearFakeCursor(vim); } // Remove any trailing newlines from the selection. For @@ -3265,6 +3374,49 @@ return { start: Pos(cur.line, start), end: Pos(cur.line, end) }; } + /** + * Depends on the following: + * + * - editor mode should be htmlmixedmode / xml + * - mode/xml/xml.js should be loaded + * - addon/fold/xml-fold.js should be loaded + * + * If any of the above requirements are not true, this function noops. + * + * This is _NOT_ a 100% accurate implementation of vim tag text objects. + * The following caveats apply (based off cursory testing, I'm sure there + * are other discrepancies): + * + * - Does not work inside comments: + * ``` + * + * ``` + * - Does not work when tags have different cases: + * ``` + *
    broken
    + * ``` + * - Does not work when cursor is inside a broken tag: + * ``` + *
    + * ``` + */ + function expandTagUnderCursor(cm, head, inclusive) { + var cur = head; + if (!CodeMirror.findMatchingTag || !CodeMirror.findEnclosingTag) { + return { start: cur, end: cur }; + } + + var tags = CodeMirror.findMatchingTag(cm, head) || CodeMirror.findEnclosingTag(cm, head); + if (!tags || !tags.open || !tags.close) { + return { start: cur, end: cur }; + } + + if (inclusive) { + return { start: tags.open.from, end: tags.close.to }; + } + return { start: tags.open.to, end: tags.close.from }; + } + function recordJumpPosition(cm, oldCur, newCur) { if (!cursorEqual(oldCur, newCur)) { vimGlobalState.jumpList.add(cm, oldCur, newCur); @@ -3532,6 +3684,18 @@ } } + function moveToEol(cm, head, motionArgs, vim, keepHPos) { + var cur = head; + var retval= Pos(cur.line + motionArgs.repeat - 1, Infinity); + var end=cm.clipPos(retval); + end.ch--; + if (!keepHPos) { + vim.lastHPos = Infinity; + vim.lastHSPos = cm.charCoords(end,'div').left; + } + return retval; + } + function moveToCharacter(cm, repeat, forward, character) { var cur = cm.getCursor(); var start = cur.ch; @@ -3806,7 +3970,7 @@ return Pos(curr_index.ln, curr_index.pos); } - // TODO: perhaps this finagling of start and end positions belonds + // TODO: perhaps this finagling of start and end positions belongs // in codemirror/replaceRange? function selectCompanionObject(cm, head, symb, inclusive) { var cur = head, start, end; @@ -4152,7 +4316,8 @@ } function makePrompt(prefix, desc) { var raw = '' + - (prefix || "") + ''; + (prefix || "") + ''; if (desc) raw += ' ' + desc + ''; return raw; @@ -4272,6 +4437,42 @@ return cursor.from(); }); } + /** + * Pretty much the same as `findNext`, except for the following differences: + * + * 1. Before starting the search, move to the previous search. This way if our cursor is + * already inside a match, we should return the current match. + * 2. Rather than only returning the cursor's from, we return the cursor's from and to as a tuple. + */ + function findNextFromAndToInclusive(cm, prev, query, repeat, vim) { + if (repeat === undefined) { repeat = 1; } + return cm.operation(function() { + var pos = cm.getCursor(); + var cursor = cm.getSearchCursor(query, pos); + + // Go back one result to ensure that if the cursor is currently a match, we keep it. + var found = cursor.find(!prev); + + // If we haven't moved, go back one more (similar to if i==0 logic in findNext). + if (!vim.visualMode && found && cursorEqual(cursor.from(), pos)) { + cursor.find(!prev); + } + + for (var i = 0; i < repeat; i++) { + found = cursor.find(prev); + if (!found) { + // SearchCursor may have returned null because it hit EOF, wrap + // around and try again. + cursor = cm.getSearchCursor(query, + (prev) ? Pos(cm.lastLine()) : Pos(cm.firstLine(), 0) ); + if (!cursor.find(prev)) { + return; + } + } + } + return [cursor.from(), cursor.to()]; + }); + } function clearSearchHighlight(cm) { var state = getSearchState(cm); cm.removeOverlay(getSearchState(cm).getOverlay()); @@ -4318,25 +4519,25 @@ } function getMarkPos(cm, vim, markName) { - if (markName == '\'') { - var history = cm.doc.history.done; - var event = history[history.length - 2]; - return event && event.ranges && event.ranges[0].head; + if (markName == '\'' || markName == '`') { + return vimGlobalState.jumpList.find(cm, -1) || Pos(0, 0); } else if (markName == '.') { - if (cm.doc.history.lastModTime == 0) { - return // If no changes, bail out; don't bother to copy or reverse history array. - } else { - var changeHistory = cm.doc.history.done.filter(function(el){ if (el.changes !== undefined) { return el } }); - changeHistory.reverse(); - var lastEditPos = changeHistory[0].changes[0].to; - } - return lastEditPos; + return getLastEditPos(cm); } var mark = vim.marks[markName]; return mark && mark.find(); } + function getLastEditPos(cm) { + var done = cm.doc.history.done; + for (var i = done.length; i--;) { + if (done[i].changes) { + return copyCursor(done[i].changes[0].to); + } + } + } + var ExCommandDispatcher = function() { this.buildCommandMap_(); }; @@ -4425,7 +4626,7 @@ } // Parse command name. - var commandMatch = inputStream.match(/^(\w+)/); + var commandMatch = inputStream.match(/^(\w+|!!|@@|[!#&*<=>@~])/); if (commandMatch) { result.commandName = commandMatch[1]; } else { @@ -5323,14 +5524,34 @@ updateFakeCursor(cm); } } + /** + * Keeps track of a fake cursor to support visual mode cursor behavior. + */ function updateFakeCursor(cm) { + var className = 'cm-animate-fat-cursor'; var vim = cm.state.vim; var from = clipCursorToContent(cm, copyCursor(vim.sel.head)); var to = offsetCursor(from, 0, 1); + clearFakeCursor(vim); + // In visual mode, the cursor may be positioned over EOL. + if (from.ch == cm.getLine(from.line).length) { + var widget = document.createElement("span"); + widget.textContent = "\u00a0"; + widget.className = className; + vim.fakeCursorBookmark = cm.setBookmark(from, {widget: widget}); + } else { + vim.fakeCursor = cm.markText(from, to, {className: className}); + } + } + function clearFakeCursor(vim) { if (vim.fakeCursor) { vim.fakeCursor.clear(); + vim.fakeCursor = null; + } + if (vim.fakeCursorBookmark) { + vim.fakeCursorBookmark.clear(); + vim.fakeCursorBookmark = null; } - vim.fakeCursor = cm.markText(from, to, {className: 'cm-animate-fat-cursor'}); } function handleExternalSelection(cm, vim) { var anchor = cm.getCursor('anchor'); diff --git a/scripts/codemirror/lib/codemirror.css b/scripts/codemirror/lib/codemirror.css index c7a8ae7..a64f97c 100644 --- a/scripts/codemirror/lib/codemirror.css +++ b/scripts/codemirror/lib/codemirror.css @@ -13,7 +13,8 @@ .CodeMirror-lines { padding: 4px 0; /* Vertical padding around content */ } -.CodeMirror pre { +.CodeMirror pre.CodeMirror-line, +.CodeMirror pre.CodeMirror-line-like { padding: 0 4px; /* Horizontal padding of content */ } @@ -96,7 +97,7 @@ .CodeMirror-rulers { position: absolute; - left: 0; right: 0; top: -50px; bottom: -20px; + left: 0; right: 0; top: -50px; bottom: 0; overflow: hidden; } .CodeMirror-ruler { @@ -163,17 +164,17 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} .CodeMirror-scroll { overflow: scroll !important; /* Things will break if this is overridden */ - /* 30px is the magic margin used to hide the element's real scrollbars */ + /* 50px is the magic margin used to hide the element's real scrollbars */ /* See overflow: hidden in .CodeMirror */ - margin-bottom: -30px; margin-right: -30px; - padding-bottom: 30px; + margin-bottom: -50px; margin-right: -50px; + padding-bottom: 50px; height: 100%; outline: none; /* Prevent dragging from highlighting the element */ position: relative; } .CodeMirror-sizer { position: relative; - border-right: 30px solid transparent; + border-right: 50px solid transparent; } /* The fake, visible scrollbars. Used to force redraw during scrolling @@ -183,6 +184,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} position: absolute; z-index: 6; display: none; + outline: none; } .CodeMirror-vscrollbar { right: 0; top: 0; @@ -211,7 +213,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} height: 100%; display: inline-block; vertical-align: top; - margin-bottom: -30px; + margin-bottom: -50px; } .CodeMirror-gutter-wrapper { position: absolute; @@ -236,7 +238,8 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} cursor: text; min-height: 1px; /* prevents collapsing before first draw */ } -.CodeMirror pre { +.CodeMirror pre.CodeMirror-line, +.CodeMirror pre.CodeMirror-line-like { /* Reset some styles that the rest of the page might have set */ -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; border-width: 0; @@ -255,7 +258,8 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} -webkit-font-variant-ligatures: contextual; font-variant-ligatures: contextual; } -.CodeMirror-wrap pre { +.CodeMirror-wrap pre.CodeMirror-line, +.CodeMirror-wrap pre.CodeMirror-line-like { word-wrap: break-word; white-space: pre-wrap; word-break: normal; diff --git a/scripts/codemirror/lib/codemirror.js b/scripts/codemirror/lib/codemirror.js index 7399e52..88a9324 100644 --- a/scripts/codemirror/lib/codemirror.js +++ b/scripts/codemirror/lib/codemirror.js @@ -10,7 +10,7 @@ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : - (global.CodeMirror = factory()); + (global = global || self, global.CodeMirror = factory()); }(this, (function () { 'use strict'; // Kludges for bugs and behavior differences that can't be feature @@ -173,10 +173,28 @@ } } - var Delayed = function() {this.id = null;}; + var Delayed = function() { + this.id = null; + this.f = null; + this.time = 0; + this.handler = bind(this.onTimeout, this); + }; + Delayed.prototype.onTimeout = function (self) { + self.id = 0; + if (self.time <= +new Date) { + self.f(); + } else { + setTimeout(self.handler, self.time - +new Date); + } + }; Delayed.prototype.set = function (ms, f) { - clearTimeout(this.id); - this.id = setTimeout(f, ms); + this.f = f; + var time = +new Date + ms; + if (!this.id || time < this.time) { + clearTimeout(this.id); + this.id = setTimeout(this.handler, ms); + this.time = time; + } }; function indexOf(array, elt) { @@ -186,7 +204,7 @@ } // Number of pixels added to scroller and sizer to hide scrollbar - var scrollerGap = 30; + var scrollerGap = 50; // Returned or thrown by various protocols to signal 'I'm not // handling this'. @@ -467,14 +485,15 @@ for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {} order.push(new BidiSpan(0, start, i$7)); } else { - var pos = i$7, at = order.length; + var pos = i$7, at = order.length, isRTL = direction == "rtl" ? 1 : 0; for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {} for (var j$2 = pos; j$2 < i$7;) { if (countsAsNum.test(types[j$2])) { - if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)); } + if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)); at += isRTL; } var nstart = j$2; for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {} order.splice(at, 0, new BidiSpan(2, nstart, j$2)); + at += isRTL; pos = j$2; } else { ++j$2; } } @@ -518,8 +537,8 @@ } else if (emitter.attachEvent) { emitter.attachEvent("on" + type, f); } else { - var map$$1 = emitter._handlers || (emitter._handlers = {}); - map$$1[type] = (map$$1[type] || noHandlers).concat(f); + var map = emitter._handlers || (emitter._handlers = {}); + map[type] = (map[type] || noHandlers).concat(f); } }; @@ -533,11 +552,11 @@ } else if (emitter.detachEvent) { emitter.detachEvent("on" + type, f); } else { - var map$$1 = emitter._handlers, arr = map$$1 && map$$1[type]; + var map = emitter._handlers, arr = map && map[type]; if (arr) { var index = indexOf(arr, f); if (index > -1) - { map$$1[type] = arr.slice(0, index).concat(arr.slice(index + 1)); } + { map[type] = arr.slice(0, index).concat(arr.slice(index + 1)); } } } } @@ -665,11 +684,11 @@ try { return te.selectionStart != te.selectionEnd } catch(e) { return false } } : function (te) { - var range$$1; - try {range$$1 = te.ownerDocument.selection.createRange();} + var range; + try {range = te.ownerDocument.selection.createRange();} catch(e) {} - if (!range$$1 || range$$1.parentElement() != te) { return false } - return range$$1.compareEndPoints("StartToEnd", range$$1) != 0 + if (!range || range.parentElement() != te) { return false } + return range.compareEndPoints("StartToEnd", range) != 0 }; var hasCopyEvent = (function () { @@ -817,10 +836,8 @@ return this.pos > start }; StringStream.prototype.eatSpace = function () { - var this$1 = this; - var start = this.pos; - while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this$1.pos; } + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this.pos; } return this.pos > start }; StringStream.prototype.skipToEnd = function () {this.pos = this.string.length;}; @@ -1016,11 +1033,9 @@ }; Context.prototype.baseToken = function (n) { - var this$1 = this; - if (!this.baseTokens) { return null } while (this.baseTokens[this.baseTokenPos] <= n) - { this$1.baseTokenPos += 2; } + { this.baseTokenPos += 2; } var type = this.baseTokens[this.baseTokenPos + 1]; return {type: type && type.replace(/( |^)overlay .*/, ""), size: this.baseTokens[this.baseTokenPos] - n} @@ -1186,7 +1201,7 @@ var prop = lineClass[1] ? "bgClass" : "textClass"; if (output[prop] == null) { output[prop] = lineClass[2]; } - else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop])) + else if (!(new RegExp("(?:^|\\s)" + lineClass[2] + "(?:$|\\s)")).test(output[prop])) { output[prop] += " " + lineClass[2]; } } } return type @@ -1509,8 +1524,8 @@ // Test whether there exists a collapsed span that partially // overlaps (covers the start or end, but not both) of a new span. // Such overlap is not allowed. - function conflictingCollapsedRange(doc, lineNo$$1, from, to, marker) { - var line = getLine(doc, lineNo$$1); + function conflictingCollapsedRange(doc, lineNo, from, to, marker) { + var line = getLine(doc, lineNo); var sps = sawCollapsedSpans && line.markedSpans; if (sps) { for (var i = 0; i < sps.length; ++i) { var sp = sps[i]; @@ -1826,7 +1841,7 @@ } } builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32; - if (style || startStyle || endStyle || mustWrap || css) { + if (style || startStyle || endStyle || mustWrap || css || attributes) { var fullStyle = style || ""; if (startStyle) { fullStyle += startStyle; } if (endStyle) { fullStyle += endStyle; } @@ -2191,10 +2206,10 @@ function updateLineWidgets(cm, lineView, dims) { if (lineView.alignable) { lineView.alignable = null; } + var isWidget = classTest("CodeMirror-linewidget"); for (var node = lineView.node.firstChild, next = (void 0); node; node = next) { next = node.nextSibling; - if (node.className == "CodeMirror-linewidget") - { lineView.node.removeChild(node); } + if (isWidget.test(node.className)) { lineView.node.removeChild(node); } } insertLineWidgets(cm, lineView, dims); } @@ -2224,7 +2239,7 @@ if (!line.widgets) { return } var wrap = ensureLineWrapped(lineView); for (var i = 0, ws = line.widgets; i < ws.length; ++i) { - var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget"); + var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget" + (widget.className ? " " + widget.className : "")); if (!widget.handleMouseEvents) { node.setAttribute("cm-ignore-events", "true"); } positionLineWidget(widget, node, lineView, dims); cm.display.input.setUneditable(node); @@ -2284,7 +2299,7 @@ function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight} function paddingH(display) { if (display.cachedPaddingH) { return display.cachedPaddingH } - var e = removeChildrenAndAdd(display.measure, elt("pre", "x")); + var e = removeChildrenAndAdd(display.measure, elt("pre", "x", "CodeMirror-line-like")); var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle; var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)}; if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data; } @@ -2412,36 +2427,36 @@ var nullRect = {left: 0, right: 0, top: 0, bottom: 0}; - function nodeAndOffsetInLineMap(map$$1, ch, bias) { + function nodeAndOffsetInLineMap(map, ch, bias) { var node, start, end, collapse, mStart, mEnd; // First, search the line map for the text node corresponding to, // or closest to, the target character. - for (var i = 0; i < map$$1.length; i += 3) { - mStart = map$$1[i]; - mEnd = map$$1[i + 1]; + for (var i = 0; i < map.length; i += 3) { + mStart = map[i]; + mEnd = map[i + 1]; if (ch < mStart) { start = 0; end = 1; collapse = "left"; } else if (ch < mEnd) { start = ch - mStart; end = start + 1; - } else if (i == map$$1.length - 3 || ch == mEnd && map$$1[i + 3] > ch) { + } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) { end = mEnd - mStart; start = end - 1; if (ch >= mEnd) { collapse = "right"; } } if (start != null) { - node = map$$1[i + 2]; + node = map[i + 2]; if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right")) { collapse = bias; } if (bias == "left" && start == 0) - { while (i && map$$1[i - 2] == map$$1[i - 3] && map$$1[i - 1].insertLeft) { - node = map$$1[(i -= 3) + 2]; + { while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) { + node = map[(i -= 3) + 2]; collapse = "left"; } } if (bias == "right" && start == mEnd - mStart) - { while (i < map$$1.length - 3 && map$$1[i + 3] == map$$1[i + 4] && !map$$1[i + 5].insertLeft) { - node = map$$1[(i += 3) + 2]; + { while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) { + node = map[(i += 3) + 2]; collapse = "right"; } } break @@ -2678,7 +2693,7 @@ function PosWithInfo(line, ch, sticky, outside, xRel) { var pos = Pos(line, ch, sticky); pos.xRel = xRel; - if (outside) { pos.outside = true; } + if (outside) { pos.outside = outside; } return pos } @@ -2687,16 +2702,16 @@ function coordsChar(cm, x, y) { var doc = cm.doc; y += cm.display.viewOffset; - if (y < 0) { return PosWithInfo(doc.first, 0, null, true, -1) } + if (y < 0) { return PosWithInfo(doc.first, 0, null, -1, -1) } var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1; if (lineN > last) - { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, true, 1) } + { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, 1, 1) } if (x < 0) { x = 0; } var lineObj = getLine(doc, lineN); for (;;) { var found = coordsCharInner(cm, lineObj, lineN, x, y); - var collapsed = collapsedSpanAround(lineObj, found.ch + (found.xRel > 0 ? 1 : 0)); + var collapsed = collapsedSpanAround(lineObj, found.ch + (found.xRel > 0 || found.outside > 0 ? 1 : 0)); if (!collapsed) { return found } var rangeEnd = collapsed.find(1); if (rangeEnd.line == lineN) { return rangeEnd } @@ -2724,13 +2739,13 @@ return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x } - function coordsCharInner(cm, lineObj, lineNo$$1, x, y) { + function coordsCharInner(cm, lineObj, lineNo, x, y) { // Move y into line-local coordinate space y -= heightAtLine(lineObj); var preparedMeasure = prepareMeasureForLine(cm, lineObj); // When directly calling `measureCharPrepared`, we have to adjust // for the widgets at this line. - var widgetHeight$$1 = widgetTopHeight(lineObj); + var widgetHeight = widgetTopHeight(lineObj); var begin = 0, end = lineObj.text.length, ltr = true; var order = getOrder(lineObj, cm.doc.direction); @@ -2738,7 +2753,7 @@ // which bidi section the coordinates fall into. if (order) { var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart) - (cm, lineObj, lineNo$$1, preparedMeasure, order, x, y); + (cm, lineObj, lineNo, preparedMeasure, order, x, y); ltr = part.level != 1; // The awkward -1 offsets are needed because findFirst (called // on these below) will treat its first bound as inclusive, @@ -2754,7 +2769,7 @@ var chAround = null, boxAround = null; var ch = findFirst(function (ch) { var box = measureCharPrepared(cm, preparedMeasure, ch); - box.top += widgetHeight$$1; box.bottom += widgetHeight$$1; + box.top += widgetHeight; box.bottom += widgetHeight; if (!boxIsAfter(box, x, y, false)) { return false } if (box.top <= y && box.left <= x) { chAround = ch; @@ -2778,27 +2793,27 @@ // left of the character and compare it's vertical position to the // coordinates sticky = ch == 0 ? "after" : ch == lineObj.text.length ? "before" : - (measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight$$1 <= y) == ltr ? + (measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight <= y) == ltr ? "after" : "before"; // Now get accurate coordinates for this place, in order to get a // base X position - var coords = cursorCoords(cm, Pos(lineNo$$1, ch, sticky), "line", lineObj, preparedMeasure); + var coords = cursorCoords(cm, Pos(lineNo, ch, sticky), "line", lineObj, preparedMeasure); baseX = coords.left; - outside = y < coords.top || y >= coords.bottom; + outside = y < coords.top ? -1 : y >= coords.bottom ? 1 : 0; } ch = skipExtendingChars(lineObj.text, ch, 1); - return PosWithInfo(lineNo$$1, ch, sticky, outside, x - baseX) + return PosWithInfo(lineNo, ch, sticky, outside, x - baseX) } - function coordsBidiPart(cm, lineObj, lineNo$$1, preparedMeasure, order, x, y) { + function coordsBidiPart(cm, lineObj, lineNo, preparedMeasure, order, x, y) { // Bidi parts are sorted left-to-right, and in a non-line-wrapping // situation, we can take this ordering to correspond to the visual // ordering. This finds the first part whose end is after the given // coordinates. var index = findFirst(function (i) { var part = order[i], ltr = part.level != 1; - return boxIsAfter(cursorCoords(cm, Pos(lineNo$$1, ltr ? part.to : part.from, ltr ? "before" : "after"), + return boxIsAfter(cursorCoords(cm, Pos(lineNo, ltr ? part.to : part.from, ltr ? "before" : "after"), "line", lineObj, preparedMeasure), x, y, true) }, 0, order.length - 1); var part = order[index]; @@ -2807,7 +2822,7 @@ // that start, move one part back. if (index > 0) { var ltr = part.level != 1; - var start = cursorCoords(cm, Pos(lineNo$$1, ltr ? part.from : part.to, ltr ? "after" : "before"), + var start = cursorCoords(cm, Pos(lineNo, ltr ? part.from : part.to, ltr ? "after" : "before"), "line", lineObj, preparedMeasure); if (boxIsAfter(start, x, y, true) && start.top > y) { part = order[index - 1]; } @@ -2853,7 +2868,7 @@ function textHeight(display) { if (display.cachedTextHeight != null) { return display.cachedTextHeight } if (measureText == null) { - measureText = elt("pre"); + measureText = elt("pre", null, "CodeMirror-line-like"); // Measure a bunch of lines, for browsers that compute // fractional heights. for (var i = 0; i < 49; ++i) { @@ -2873,7 +2888,7 @@ function charWidth(display) { if (display.cachedCharWidth != null) { return display.cachedCharWidth } var anchor = elt("span", "xxxxxxxxxx"); - var pre = elt("pre", [anchor]); + var pre = elt("pre", [anchor], "CodeMirror-line-like"); removeChildrenAndAdd(display.measure, pre); var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10; if (width > 2) { display.cachedCharWidth = width; } @@ -2945,9 +2960,9 @@ var x, y, space = display.lineSpace.getBoundingClientRect(); // Fails unpredictably on IE[67] when mouse is dragged around quickly. try { x = e.clientX - space.left; y = e.clientY - space.top; } - catch (e) { return null } + catch (e$1) { return null } var coords = coordsChar(cm, x, y), line; - if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) { + if (forRect && coords.xRel > 0 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) { var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length; coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff)); } @@ -3128,13 +3143,13 @@ for (var i = 0; i < doc.sel.ranges.length; i++) { if (!primary && i == doc.sel.primIndex) { continue } - var range$$1 = doc.sel.ranges[i]; - if (range$$1.from().line >= cm.display.viewTo || range$$1.to().line < cm.display.viewFrom) { continue } - var collapsed = range$$1.empty(); + var range = doc.sel.ranges[i]; + if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) { continue } + var collapsed = range.empty(); if (collapsed || cm.options.showCursorWhenSelecting) - { drawSelectionCursor(cm, range$$1.head, curFragment); } + { drawSelectionCursor(cm, range.head, curFragment); } if (!collapsed) - { drawSelectionRange(cm, range$$1, selFragment); } + { drawSelectionRange(cm, range, selFragment); } } return result } @@ -3161,7 +3176,7 @@ function cmpCoords(a, b) { return a.top - b.top || a.left - b.left } // Draws the given range as a highlighted selection - function drawSelectionRange(cm, range$$1, output) { + function drawSelectionRange(cm, range, output) { var display = cm.display, doc = cm.doc; var fragment = document.createDocumentFragment(); var padding = paddingH(cm.display), leftSide = padding.left; @@ -3230,7 +3245,7 @@ return {start: start, end: end} } - var sFrom = range$$1.from(), sTo = range$$1.to(); + var sFrom = range.from(), sTo = range.to(); if (sFrom.line == sTo.line) { drawForLine(sFrom.line, sFrom.ch, sTo.ch); } else { @@ -3261,8 +3276,10 @@ var on = true; display.cursorDiv.style.visibility = ""; if (cm.options.cursorBlinkRate > 0) - { display.blinker = setInterval(function () { return display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; }, - cm.options.cursorBlinkRate); } + { display.blinker = setInterval(function () { + if (!cm.hasFocus()) { onBlur(cm); } + display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; + }, cm.options.cursorBlinkRate); } else if (cm.options.cursorBlinkRate < 0) { display.cursorDiv.style.visibility = "hidden"; } } @@ -3497,9 +3514,9 @@ if (y != null) { cm.curOp.scrollTop = y; } } - function scrollToRange(cm, range$$1) { + function scrollToRange(cm, range) { resolveScrollToPos(cm); - cm.curOp.scrollToPos = range$$1; + cm.curOp.scrollToPos = range; } // When an operation has its scrollToPos property set, and another @@ -3507,11 +3524,11 @@ // 'simulates' scrolling that position into view in a cheap way, so // that the effect of intermediate scroll commands is not ignored. function resolveScrollToPos(cm) { - var range$$1 = cm.curOp.scrollToPos; - if (range$$1) { + var range = cm.curOp.scrollToPos; + if (range) { cm.curOp.scrollToPos = null; - var from = estimateCoords(cm, range$$1.from), to = estimateCoords(cm, range$$1.to); - scrollToCoordsRange(cm, from, to, range$$1.margin); + var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to); + scrollToCoordsRange(cm, from, to, range.margin); } } @@ -3536,7 +3553,7 @@ } function setScrollTop(cm, val, forceScroll) { - val = Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val); + val = Math.max(0, Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val)); if (cm.display.scroller.scrollTop == val && !forceScroll) { return } cm.doc.scrollTop = val; cm.display.scrollbars.setScrollTop(val); @@ -3546,7 +3563,7 @@ // Sync scroller and scrollbar, ensure the gutter elements are // aligned. function setScrollLeft(cm, val, isScroller, forceScroll) { - val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth); + val = Math.max(0, Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth)); if ((isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) && !forceScroll) { return } cm.doc.scrollLeft = val; alignHorizontally(cm); @@ -3658,9 +3675,9 @@ // (when the bar is hidden). If it is still visible, we keep // it enabled, if it's hidden, we disable pointer events. var box = bar.getBoundingClientRect(); - var elt$$1 = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2) + var elt = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2) : document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1); - if (elt$$1 != bar) { bar.style.pointerEvents = "none"; } + if (elt != bar) { bar.style.pointerEvents = "none"; } else { delay.set(1000, maybeDisable); } } delay.set(1000, maybeDisable); @@ -4000,10 +4017,8 @@ { this.events.push(arguments); } }; DisplayUpdate.prototype.finish = function () { - var this$1 = this; - for (var i = 0; i < this.events.length; i++) - { signal.apply(null, this$1.events[i]); } + { signal.apply(null, this.events[i]); } }; function maybeClipScrollbars(cm) { @@ -4037,12 +4052,13 @@ function restoreSelection(snapshot) { if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return } snapshot.activeElt.focus(); - if (snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) { - var sel = window.getSelection(), range$$1 = document.createRange(); - range$$1.setEnd(snapshot.anchorNode, snapshot.anchorOffset); - range$$1.collapse(false); + if (!/^(INPUT|TEXTAREA)$/.test(snapshot.activeElt.nodeName) && + snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) { + var sel = window.getSelection(), range = document.createRange(); + range.setEnd(snapshot.anchorNode, snapshot.anchorOffset); + range.collapse(false); sel.removeAllRanges(); - sel.addRange(range$$1); + sel.addRange(range); sel.extend(snapshot.focusNode, snapshot.focusOffset); } } @@ -4135,6 +4151,8 @@ update.visible = visibleLines(cm.display, cm.doc, viewport); if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo) { break } + } else if (first) { + update.visible = visibleLines(cm.display, cm.doc, viewport); } if (!updateDisplayIfNeeded(cm, update)) { break } updateHeightsInViewport(cm); @@ -4535,40 +4553,32 @@ Selection.prototype.primary = function () { return this.ranges[this.primIndex] }; Selection.prototype.equals = function (other) { - var this$1 = this; - if (other == this) { return true } if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false } for (var i = 0; i < this.ranges.length; i++) { - var here = this$1.ranges[i], there = other.ranges[i]; + var here = this.ranges[i], there = other.ranges[i]; if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) { return false } } return true }; Selection.prototype.deepCopy = function () { - var this$1 = this; - var out = []; for (var i = 0; i < this.ranges.length; i++) - { out[i] = new Range(copyPos(this$1.ranges[i].anchor), copyPos(this$1.ranges[i].head)); } + { out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)); } return new Selection(out, this.primIndex) }; Selection.prototype.somethingSelected = function () { - var this$1 = this; - for (var i = 0; i < this.ranges.length; i++) - { if (!this$1.ranges[i].empty()) { return true } } + { if (!this.ranges[i].empty()) { return true } } return false }; Selection.prototype.contains = function (pos, end) { - var this$1 = this; - if (!end) { end = pos; } for (var i = 0; i < this.ranges.length; i++) { - var range = this$1.ranges[i]; + var range = this.ranges[i]; if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0) { return i } } @@ -4694,16 +4704,16 @@ } // Perform a change on the document data structure. - function updateDoc(doc, change, markedSpans, estimateHeight$$1) { + function updateDoc(doc, change, markedSpans, estimateHeight) { function spansFor(n) {return markedSpans ? markedSpans[n] : null} function update(line, text, spans) { - updateLine(line, text, spans, estimateHeight$$1); + updateLine(line, text, spans, estimateHeight); signalLater(line, "change", line, change); } function linesFor(start, end) { var result = []; for (var i = start; i < end; ++i) - { result.push(new Line(text[i], spansFor(i), estimateHeight$$1)); } + { result.push(new Line(text[i], spansFor(i), estimateHeight)); } return result } @@ -4727,7 +4737,7 @@ update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans); } else { var added$1 = linesFor(1, text.length - 1); - added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight$$1)); + added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)); update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); doc.insert(from.line + 1, added$1); } @@ -5064,11 +5074,9 @@ var obj = { ranges: sel.ranges, update: function(ranges) { - var this$1 = this; - this.ranges = []; for (var i = 0; i < ranges.length; i++) - { this$1.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), + { this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), clipPos(doc, ranges[i].head)); } }, origin: options && options.origin @@ -5403,6 +5411,9 @@ if (doc.cm) { makeChangeSingleDocInEditor(doc.cm, change, spans); } else { updateDoc(doc, change, spans); } setSelectionNoUndo(doc, selAfter, sel_dontScroll); + + if (doc.cantEdit && skipAtomic(doc, Pos(doc.firstLine(), 0))) + { doc.cantEdit = false; } } // Handle the interaction of a change to a document with the editor @@ -5552,13 +5563,11 @@ // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html function LeafChunk(lines) { - var this$1 = this; - this.lines = lines; this.parent = null; var height = 0; for (var i = 0; i < lines.length; ++i) { - lines[i].parent = this$1; + lines[i].parent = this; height += lines[i].height; } this.height = height; @@ -5569,11 +5578,9 @@ // Remove the n lines at offset 'at'. removeInner: function(at, n) { - var this$1 = this; - for (var i = at, e = at + n; i < e; ++i) { - var line = this$1.lines[i]; - this$1.height -= line.height; + var line = this.lines[i]; + this.height -= line.height; cleanUpLine(line); signalLater(line, "delete"); } @@ -5588,31 +5595,25 @@ // Insert the given array of lines at offset 'at', count them as // having the given height. insertInner: function(at, lines, height) { - var this$1 = this; - this.height += height; this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at)); - for (var i = 0; i < lines.length; ++i) { lines[i].parent = this$1; } + for (var i = 0; i < lines.length; ++i) { lines[i].parent = this; } }, // Used to iterate over a part of the tree. iterN: function(at, n, op) { - var this$1 = this; - for (var e = at + n; at < e; ++at) - { if (op(this$1.lines[at])) { return true } } + { if (op(this.lines[at])) { return true } } } }; function BranchChunk(children) { - var this$1 = this; - this.children = children; var size = 0, height = 0; for (var i = 0; i < children.length; ++i) { var ch = children[i]; size += ch.chunkSize(); height += ch.height; - ch.parent = this$1; + ch.parent = this; } this.size = size; this.height = height; @@ -5623,16 +5624,14 @@ chunkSize: function() { return this.size }, removeInner: function(at, n) { - var this$1 = this; - this.size -= n; for (var i = 0; i < this.children.length; ++i) { - var child = this$1.children[i], sz = child.chunkSize(); + var child = this.children[i], sz = child.chunkSize(); if (at < sz) { var rm = Math.min(n, sz - at), oldHeight = child.height; child.removeInner(at, rm); - this$1.height -= oldHeight - child.height; - if (sz == rm) { this$1.children.splice(i--, 1); child.parent = null; } + this.height -= oldHeight - child.height; + if (sz == rm) { this.children.splice(i--, 1); child.parent = null; } if ((n -= rm) == 0) { break } at = 0; } else { at -= sz; } @@ -5649,18 +5648,14 @@ }, collapse: function(lines) { - var this$1 = this; - - for (var i = 0; i < this.children.length; ++i) { this$1.children[i].collapse(lines); } + for (var i = 0; i < this.children.length; ++i) { this.children[i].collapse(lines); } }, insertInner: function(at, lines, height) { - var this$1 = this; - this.size += lines.length; this.height += height; for (var i = 0; i < this.children.length; ++i) { - var child = this$1.children[i], sz = child.chunkSize(); + var child = this.children[i], sz = child.chunkSize(); if (at <= sz) { child.insertInner(at, lines, height); if (child.lines && child.lines.length > 50) { @@ -5670,11 +5665,11 @@ for (var pos = remaining; pos < child.lines.length;) { var leaf = new LeafChunk(child.lines.slice(pos, pos += 25)); child.height -= leaf.height; - this$1.children.splice(++i, 0, leaf); - leaf.parent = this$1; + this.children.splice(++i, 0, leaf); + leaf.parent = this; } child.lines = child.lines.slice(0, remaining); - this$1.maybeSpill(); + this.maybeSpill(); } break } @@ -5706,10 +5701,8 @@ }, iterN: function(at, n, op) { - var this$1 = this; - for (var i = 0; i < this.children.length; ++i) { - var child = this$1.children[i], sz = child.chunkSize(); + var child = this.children[i], sz = child.chunkSize(); if (at < sz) { var used = Math.min(n, sz - at); if (child.iterN(at, used, op)) { return true } @@ -5723,20 +5716,16 @@ // Line widgets are block elements displayed above or below a line. var LineWidget = function(doc, node, options) { - var this$1 = this; - if (options) { for (var opt in options) { if (options.hasOwnProperty(opt)) - { this$1[opt] = options[opt]; } } } + { this[opt] = options[opt]; } } } this.doc = doc; this.node = node; }; LineWidget.prototype.clear = function () { - var this$1 = this; - var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line); if (no == null || !ws) { return } - for (var i = 0; i < ws.length; ++i) { if (ws[i] == this$1) { ws.splice(i--, 1); } } + for (var i = 0; i < ws.length; ++i) { if (ws[i] == this) { ws.splice(i--, 1); } } if (!ws.length) { line.widgets = null; } var height = widgetHeight(this); updateLineHeight(line, Math.max(0, line.height - height)); @@ -5819,8 +5808,6 @@ // Clear the marker. TextMarker.prototype.clear = function () { - var this$1 = this; - if (this.explicitlyCleared) { return } var cm = this.doc.cm, withOp = cm && !cm.curOp; if (withOp) { startOperation(cm); } @@ -5830,19 +5817,19 @@ } var min = null, max = null; for (var i = 0; i < this.lines.length; ++i) { - var line = this$1.lines[i]; - var span = getMarkedSpanFor(line.markedSpans, this$1); - if (cm && !this$1.collapsed) { regLineChange(cm, lineNo(line), "text"); } + var line = this.lines[i]; + var span = getMarkedSpanFor(line.markedSpans, this); + if (cm && !this.collapsed) { regLineChange(cm, lineNo(line), "text"); } else if (cm) { if (span.to != null) { max = lineNo(line); } if (span.from != null) { min = lineNo(line); } } line.markedSpans = removeMarkedSpan(line.markedSpans, span); - if (span.from == null && this$1.collapsed && !lineIsHidden(this$1.doc, line) && cm) + if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm) { updateLineHeight(line, textHeight(cm.display)); } } if (cm && this.collapsed && !cm.options.lineWrapping) { for (var i$1 = 0; i$1 < this.lines.length; ++i$1) { - var visual = visualLine(this$1.lines[i$1]), len = lineLength(visual); + var visual = visualLine(this.lines[i$1]), len = lineLength(visual); if (len > cm.display.maxLineLength) { cm.display.maxLine = visual; cm.display.maxLineLength = len; @@ -5868,13 +5855,11 @@ // Pos objects returned contain a line object, rather than a line // number (used to prevent looking up the same line twice). TextMarker.prototype.find = function (side, lineObj) { - var this$1 = this; - if (side == null && this.type == "bookmark") { side = 1; } var from, to; for (var i = 0; i < this.lines.length; ++i) { - var line = this$1.lines[i]; - var span = getMarkedSpanFor(line.markedSpans, this$1); + var line = this.lines[i]; + var span = getMarkedSpanFor(line.markedSpans, this); if (span.from != null) { from = Pos(lineObj ? line : lineNo(line), span.from); if (side == -1) { return from } @@ -6008,21 +5993,17 @@ // implemented as a meta-marker-object controlling multiple normal // markers. var SharedTextMarker = function(markers, primary) { - var this$1 = this; - this.markers = markers; this.primary = primary; for (var i = 0; i < markers.length; ++i) - { markers[i].parent = this$1; } + { markers[i].parent = this; } }; SharedTextMarker.prototype.clear = function () { - var this$1 = this; - if (this.explicitlyCleared) { return } this.explicitlyCleared = true; for (var i = 0; i < this.markers.length; ++i) - { this$1.markers[i].clear(); } + { this.markers[i].clear(); } signalLater(this, "clear"); }; @@ -6165,11 +6146,11 @@ clipPos: function(pos) {return clipPos(this, pos)}, getCursor: function(start) { - var range$$1 = this.sel.primary(), pos; - if (start == null || start == "head") { pos = range$$1.head; } - else if (start == "anchor") { pos = range$$1.anchor; } - else if (start == "end" || start == "to" || start === false) { pos = range$$1.to(); } - else { pos = range$$1.from(); } + var range = this.sel.primary(), pos; + if (start == null || start == "head") { pos = range.head; } + else if (start == "anchor") { pos = range.anchor; } + else if (start == "end" || start == "to" || start === false) { pos = range.to(); } + else { pos = range.from(); } return pos }, listSelections: function() { return this.sel.ranges }, @@ -6192,13 +6173,11 @@ extendSelections(this, clipPosArray(this, heads), options); }), setSelections: docMethodOp(function(ranges, primary, options) { - var this$1 = this; - if (!ranges.length) { return } var out = []; for (var i = 0; i < ranges.length; i++) - { out[i] = new Range(clipPos(this$1, ranges[i].anchor), - clipPos(this$1, ranges[i].head)); } + { out[i] = new Range(clipPos(this, ranges[i].anchor), + clipPos(this, ranges[i].head)); } if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex); } setSelection(this, normalizeSelection(this.cm, out, primary), options); }), @@ -6209,23 +6188,19 @@ }), getSelection: function(lineSep) { - var this$1 = this; - var ranges = this.sel.ranges, lines; for (var i = 0; i < ranges.length; i++) { - var sel = getBetween(this$1, ranges[i].from(), ranges[i].to()); + var sel = getBetween(this, ranges[i].from(), ranges[i].to()); lines = lines ? lines.concat(sel) : sel; } if (lineSep === false) { return lines } else { return lines.join(lineSep || this.lineSeparator()) } }, getSelections: function(lineSep) { - var this$1 = this; - var parts = [], ranges = this.sel.ranges; for (var i = 0; i < ranges.length; i++) { - var sel = getBetween(this$1, ranges[i].from(), ranges[i].to()); - if (lineSep !== false) { sel = sel.join(lineSep || this$1.lineSeparator()); } + var sel = getBetween(this, ranges[i].from(), ranges[i].to()); + if (lineSep !== false) { sel = sel.join(lineSep || this.lineSeparator()); } parts[i] = sel; } return parts @@ -6237,16 +6212,14 @@ this.replaceSelections(dup, collapse, origin || "+input"); }, replaceSelections: docMethodOp(function(code, collapse, origin) { - var this$1 = this; - var changes = [], sel = this.sel; for (var i = 0; i < sel.ranges.length; i++) { - var range$$1 = sel.ranges[i]; - changes[i] = {from: range$$1.from(), to: range$$1.to(), text: this$1.splitLines(code[i]), origin: origin}; + var range = sel.ranges[i]; + changes[i] = {from: range.from(), to: range.to(), text: this.splitLines(code[i]), origin: origin}; } var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse); for (var i$1 = changes.length - 1; i$1 >= 0; i$1--) - { makeChange(this$1, changes[i$1]); } + { makeChange(this, changes[i$1]); } if (newSel) { setSelectionReplaceHistory(this, newSel); } else if (this.cm) { ensureCursorVisible(this.cm); } }), @@ -6264,7 +6237,12 @@ for (var i$1 = 0; i$1 < hist.undone.length; i$1++) { if (!hist.undone[i$1].ranges) { ++undone; } } return {undo: done, redo: undone} }, - clearHistory: function() {this.history = new History(this.history.maxGeneration);}, + clearHistory: function() { + var this$1 = this; + + this.history = new History(this.history.maxGeneration); + linkedDocs(this, function (doc) { return doc.history = this$1.history; }, true); + }, markClean: function() { this.cleanGeneration = this.changeGeneration(true); @@ -6385,18 +6363,18 @@ }, findMarks: function(from, to, filter) { from = clipPos(this, from); to = clipPos(this, to); - var found = [], lineNo$$1 = from.line; + var found = [], lineNo = from.line; this.iter(from.line, to.line + 1, function (line) { var spans = line.markedSpans; if (spans) { for (var i = 0; i < spans.length; i++) { var span = spans[i]; - if (!(span.to != null && lineNo$$1 == from.line && from.ch >= span.to || - span.from == null && lineNo$$1 != from.line || - span.from != null && lineNo$$1 == to.line && span.from >= to.ch) && + if (!(span.to != null && lineNo == from.line && from.ch >= span.to || + span.from == null && lineNo != from.line || + span.from != null && lineNo == to.line && span.from >= to.ch) && (!filter || filter(span.marker))) { found.push(span.marker.parent || span.marker); } } } - ++lineNo$$1; + ++lineNo; }); return found }, @@ -6411,14 +6389,14 @@ }, posFromIndex: function(off) { - var ch, lineNo$$1 = this.first, sepSize = this.lineSeparator().length; + var ch, lineNo = this.first, sepSize = this.lineSeparator().length; this.iter(function (line) { var sz = line.text.length + sepSize; if (sz > off) { ch = off; return true } off -= sz; - ++lineNo$$1; + ++lineNo; }); - return clipPos(this, Pos(lineNo$$1, ch)) + return clipPos(this, Pos(lineNo, ch)) }, indexFromPos: function (coords) { coords = clipPos(this, coords); @@ -6457,15 +6435,13 @@ return copy }, unlinkDoc: function(other) { - var this$1 = this; - if (other instanceof CodeMirror) { other = other.doc; } if (this.linked) { for (var i = 0; i < this.linked.length; ++i) { - var link = this$1.linked[i]; + var link = this.linked[i]; if (link.doc != other) { continue } - this$1.linked.splice(i, 1); - other.unlinkDoc(this$1); - detachSharedMarkers(findSharedMarkers(this$1)); + this.linked.splice(i, 1); + other.unlinkDoc(this); + detachSharedMarkers(findSharedMarkers(this)); break } } // If the histories were shared, split them again @@ -6517,28 +6493,39 @@ // and insert it. if (files && files.length && window.FileReader && window.File) { var n = files.length, text = Array(n), read = 0; - var loadFile = function (file, i) { - if (cm.options.allowDropFileTypes && - indexOf(cm.options.allowDropFileTypes, file.type) == -1) - { return } - - var reader = new FileReader; - reader.onload = operation(cm, function () { - var content = reader.result; - if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) { content = ""; } - text[i] = content; - if (++read == n) { + var markAsReadAndPasteIfAllFilesAreRead = function () { + if (++read == n) { + operation(cm, function () { pos = clipPos(cm.doc, pos); var change = {from: pos, to: pos, - text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())), + text: cm.doc.splitLines( + text.filter(function (t) { return t != null; }).join(cm.doc.lineSeparator())), origin: "paste"}; makeChange(cm.doc, change); - setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change))); + setSelectionReplaceHistory(cm.doc, simpleSelection(clipPos(cm.doc, pos), clipPos(cm.doc, changeEnd(change)))); + })(); + } + }; + var readTextFromFile = function (file, i) { + if (cm.options.allowDropFileTypes && + indexOf(cm.options.allowDropFileTypes, file.type) == -1) { + markAsReadAndPasteIfAllFilesAreRead(); + return + } + var reader = new FileReader; + reader.onerror = function () { return markAsReadAndPasteIfAllFilesAreRead(); }; + reader.onload = function () { + var content = reader.result; + if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) { + markAsReadAndPasteIfAllFilesAreRead(); + return } - }); + text[i] = content; + markAsReadAndPasteIfAllFilesAreRead(); + }; reader.readAsText(file); }; - for (var i = 0; i < n; ++i) { loadFile(files[i], i); } + for (var i = 0; i < files.length; i++) { readTextFromFile(files[i], i); } } else { // Normal drop // Don't do a replace if the drop happened inside of the selected text. if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) { @@ -6560,7 +6547,7 @@ cm.display.input.focus(); } } - catch(e){} + catch(e$1){} } } @@ -6656,7 +6643,7 @@ 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 145: "ScrollLock", 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", - 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", + 221: "]", 222: "'", 224: "Mod", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert" }; @@ -6763,18 +6750,18 @@ return keymap } - function lookupKey(key, map$$1, handle, context) { - map$$1 = getKeyMap(map$$1); - var found = map$$1.call ? map$$1.call(key, context) : map$$1[key]; + function lookupKey(key, map, handle, context) { + map = getKeyMap(map); + var found = map.call ? map.call(key, context) : map[key]; if (found === false) { return "nothing" } if (found === "...") { return "multi" } if (found != null && handle(found)) { return "handled" } - if (map$$1.fallthrough) { - if (Object.prototype.toString.call(map$$1.fallthrough) != "[object Array]") - { return lookupKey(key, map$$1.fallthrough, handle, context) } - for (var i = 0; i < map$$1.fallthrough.length; i++) { - var result = lookupKey(key, map$$1.fallthrough[i], handle, context); + if (map.fallthrough) { + if (Object.prototype.toString.call(map.fallthrough) != "[object Array]") + { return lookupKey(key, map.fallthrough, handle, context) } + for (var i = 0; i < map.fallthrough.length; i++) { + var result = lookupKey(key, map.fallthrough[i], handle, context); if (result) { return result } } } @@ -6791,7 +6778,7 @@ var base = name; if (event.altKey && base != "Alt") { name = "Alt-" + name; } if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") { name = "Ctrl-" + name; } - if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") { name = "Cmd-" + name; } + if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Mod") { name = "Cmd-" + name; } if (!noShift && event.shiftKey && base != "Shift") { name = "Shift-" + name; } return name } @@ -6848,6 +6835,7 @@ function endOfLine(visually, cm, lineObj, lineNo, dir) { if (visually) { + if (cm.doc.direction == "rtl") { dir = -dir; } var order = getOrder(lineObj, cm.doc.direction); if (order) { var part = dir < 0 ? lst(order) : order[0]; @@ -7016,7 +7004,7 @@ goGroupRight: function (cm) { return cm.moveH(1, "group"); }, goGroupLeft: function (cm) { return cm.moveH(-1, "group"); }, goWordRight: function (cm) { return cm.moveH(1, "word"); }, - delCharBefore: function (cm) { return cm.deleteH(-1, "char"); }, + delCharBefore: function (cm) { return cm.deleteH(-1, "codepoint"); }, delCharAfter: function (cm) { return cm.deleteH(1, "char"); }, delWordBefore: function (cm) { return cm.deleteH(-1, "word"); }, delWordAfter: function (cm) { return cm.deleteH(1, "word"); }, @@ -7102,7 +7090,7 @@ var line = getLine(cm.doc, start.line); var order = getOrder(line, cm.doc.direction); if (!order || order[0].level == 0) { - var firstNonWS = Math.max(0, line.text.search(/\S/)); + var firstNonWS = Math.max(start.ch, line.text.search(/\S/)); var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch; return Pos(start.line, inWS ? 0 : firstNonWS, start.sticky) } @@ -7205,6 +7193,7 @@ var lastStoppedKey = null; function onKeyDown(e) { var cm = this; + if (e.target && e.target != cm.display.input.getField()) { return } cm.curOp.focus = activeElt(); if (signalDOMEvent(cm, e)) { return } // IE does strange things with escape. @@ -7218,6 +7207,8 @@ if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey)) { cm.replaceSelection("", null, "cut"); } } + if (gecko && !mac && !handled && code == 46 && e.shiftKey && !e.ctrlKey && document.execCommand) + { document.execCommand("cut"); } // Turn mouse into crosshair when Alt is held on Mac. if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className)) @@ -7246,6 +7237,7 @@ function onKeyPress(e) { var cm = this; + if (e.target && e.target != cm.display.input.getField()) { return } if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return } var keyCode = e.keyCode, charCode = e.charCode; if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return} @@ -7394,8 +7386,8 @@ if (!behavior.addNew) { extendSelection(cm.doc, pos, null, null, behavior.extend); } // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081) - if (webkit || ie && ie_version == 9) - { setTimeout(function () {display.wrapper.ownerDocument.body.focus(); display.input.focus();}, 20); } + if ((webkit && !safari) || ie && ie_version == 9) + { setTimeout(function () {display.wrapper.ownerDocument.body.focus({preventScroll: true}); display.input.focus();}, 20); } else { display.input.focus(); } } @@ -7449,11 +7441,11 @@ start = posFromMouse(cm, event, true, true); ourIndex = -1; } else { - var range$$1 = rangeForUnit(cm, start, behavior.unit); + var range = rangeForUnit(cm, start, behavior.unit); if (behavior.extend) - { ourRange = extendRange(ourRange, range$$1.anchor, range$$1.head, behavior.extend); } + { ourRange = extendRange(ourRange, range.anchor, range.head, behavior.extend); } else - { ourRange = range$$1; } + { ourRange = range; } } if (!behavior.addNew) { @@ -7496,14 +7488,14 @@ cm.scrollIntoView(pos); } else { var oldRange = ourRange; - var range$$1 = rangeForUnit(cm, pos, behavior.unit); + var range = rangeForUnit(cm, pos, behavior.unit); var anchor = oldRange.anchor, head; - if (cmp(range$$1.anchor, anchor) > 0) { - head = range$$1.head; - anchor = minPos(oldRange.from(), range$$1.anchor); + if (cmp(range.anchor, anchor) > 0) { + head = range.head; + anchor = minPos(oldRange.from(), range.anchor); } else { - head = range$$1.anchor; - anchor = maxPos(oldRange.to(), range$$1.head); + head = range.anchor; + anchor = maxPos(oldRange.to(), range.head); } var ranges$1 = startSel.ranges.slice(0); ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head)); @@ -7565,17 +7557,17 @@ // Used when mouse-selecting to adjust the anchor to the proper side // of a bidi jump depending on the visual position of the head. - function bidiSimplify(cm, range$$1) { - var anchor = range$$1.anchor; - var head = range$$1.head; + function bidiSimplify(cm, range) { + var anchor = range.anchor; + var head = range.head; var anchorLine = getLine(cm.doc, anchor.line); - if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range$$1 } + if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range } var order = getOrder(anchorLine); - if (!order) { return range$$1 } + if (!order) { return range } var index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index]; - if (part.from != anchor.ch && part.to != anchor.ch) { return range$$1 } + if (part.from != anchor.ch && part.to != anchor.ch) { return range } var boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1); - if (boundary == 0 || boundary == order.length) { return range$$1 } + if (boundary == 0 || boundary == order.length) { return range } // Compute the relative visual position of the head compared to the // anchor (<0 is to the left, >0 to the right) @@ -7594,7 +7586,7 @@ var usePart = order[boundary + (leftSide ? -1 : 0)]; var from = leftSide == (usePart.level == 1); var ch = from ? usePart.from : usePart.to, sticky = from ? "after" : "before"; - return anchor.ch == ch && anchor.sticky == sticky ? range$$1 : new Range(new Pos(anchor.line, ch, sticky), head) + return anchor.ch == ch && anchor.sticky == sticky ? range : new Range(new Pos(anchor.line, ch, sticky), head) } @@ -7607,7 +7599,7 @@ mY = e.touches[0].clientY; } else { try { mX = e.clientX; mY = e.clientY; } - catch(e) { return false } + catch(e$1) { return false } } if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false } if (prevent) { e_preventDefault(e); } @@ -7707,7 +7699,7 @@ for (var i = newBreaks.length - 1; i >= 0; i--) { replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)); } }); - option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff\ufff9-\ufffc]/g, function (cm, val, old) { + option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200c\u200e\u200f\u2028\u2029\ufeff\ufff9-\ufffc]/g, function (cm, val, old) { cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g"); if (old != Init) { cm.refresh(); } }); @@ -7771,6 +7763,12 @@ } cm.display.input.readOnlyChanged(val); }); + + option("screenReaderLabel", null, function (cm, val) { + val = (val === '') ? null : val; + cm.display.input.screenReaderLabelChanged(val); + }); + option("disableInput", false, function (cm, val) {if (!val) { cm.display.input.reset(); }}, true); option("dragDrop", true, dragDropChanged); option("allowDropFileTypes", null); @@ -7881,15 +7879,17 @@ attachDoc(this, doc); if ((options.autofocus && !mobile) || this.hasFocus()) - { setTimeout(bind(onFocus, this), 20); } + { setTimeout(function () { + if (this$1.hasFocus() && !this$1.state.focused) { onFocus(this$1); } + }, 20); } else { onBlur(this); } for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt)) - { optionHandlers[opt](this$1, options[opt], Init); } } + { optionHandlers[opt](this, options[opt], Init); } } maybeUpdateLineNumberWidth(this); if (options.finishInit) { options.finishInit(this); } - for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this$1); } + for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this); } endOperation(this); // Suppress optimizelegibility in Webkit, since it breaks text // measuring on line wrapping boundaries. @@ -7923,6 +7923,9 @@ // which point we can't mess with it anymore. Context menu is // handled in onMouseDown for these browsers. on(d.scroller, "contextmenu", function (e) { return onContextMenu(cm, e); }); + on(d.input.getField(), "contextmenu", function (e) { + if (!d.scroller.contains(e.target)) { onContextMenu(cm, e); } + }); // Used to suppress mouse event handling when a touch happens var touchFinished, prevTouch = {end: 0}; @@ -8111,14 +8114,14 @@ var updateInput = cm.curOp.updateInput; // Normal behavior is to insert the new text into every selection for (var i$1 = sel.ranges.length - 1; i$1 >= 0; i$1--) { - var range$$1 = sel.ranges[i$1]; - var from = range$$1.from(), to = range$$1.to(); - if (range$$1.empty()) { + var range = sel.ranges[i$1]; + var from = range.from(), to = range.to(); + if (range.empty()) { if (deleted && deleted > 0) // Handle deletion { from = Pos(from.line, from.ch - deleted); } else if (cm.state.overwrite && !paste) // Handle overwrite { to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); } - else if (paste && lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted) + else if (paste && lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == textLines.join("\n")) { from = to = Pos(from.line, 0); } } var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines, @@ -8151,21 +8154,21 @@ var sel = cm.doc.sel; for (var i = sel.ranges.length - 1; i >= 0; i--) { - var range$$1 = sel.ranges[i]; - if (range$$1.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range$$1.head.line)) { continue } - var mode = cm.getModeAt(range$$1.head); + var range = sel.ranges[i]; + if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) { continue } + var mode = cm.getModeAt(range.head); var indented = false; if (mode.electricChars) { for (var j = 0; j < mode.electricChars.length; j++) { if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) { - indented = indentLine(cm, range$$1.head.line, "smart"); + indented = indentLine(cm, range.head.line, "smart"); break } } } else if (mode.electricInput) { - if (mode.electricInput.test(getLine(cm.doc, range$$1.head.line).text.slice(0, range$$1.head.ch))) - { indented = indentLine(cm, range$$1.head.line, "smart"); } + if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch))) + { indented = indentLine(cm, range.head.line, "smart"); } } - if (indented) { signalLater(cm, "electricInput", cm, range$$1.head.line); } + if (indented) { signalLater(cm, "electricInput", cm, range.head.line); } } } @@ -8230,13 +8233,13 @@ getOption: function(option) {return this.options[option]}, getDoc: function() {return this.doc}, - addKeyMap: function(map$$1, bottom) { - this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map$$1)); + addKeyMap: function(map, bottom) { + this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map)); }, - removeKeyMap: function(map$$1) { + removeKeyMap: function(map) { var maps = this.state.keyMaps; for (var i = 0; i < maps.length; ++i) - { if (maps[i] == map$$1 || maps[i].name == map$$1) { + { if (maps[i] == map || maps[i].name == map) { maps.splice(i, 1); return true } } @@ -8253,15 +8256,13 @@ regChange(this); }), removeOverlay: methodOp(function(spec) { - var this$1 = this; - var overlays = this.state.overlays; for (var i = 0; i < overlays.length; ++i) { var cur = overlays[i].modeSpec; if (cur == spec || typeof spec == "string" && cur.name == spec) { overlays.splice(i, 1); - this$1.state.modeGen++; - regChange(this$1); + this.state.modeGen++; + regChange(this); return } } @@ -8275,24 +8276,22 @@ if (isLine(this.doc, n)) { indentLine(this, n, dir, aggressive); } }), indentSelection: methodOp(function(how) { - var this$1 = this; - var ranges = this.doc.sel.ranges, end = -1; for (var i = 0; i < ranges.length; i++) { - var range$$1 = ranges[i]; - if (!range$$1.empty()) { - var from = range$$1.from(), to = range$$1.to(); + var range = ranges[i]; + if (!range.empty()) { + var from = range.from(), to = range.to(); var start = Math.max(end, from.line); - end = Math.min(this$1.lastLine(), to.line - (to.ch ? 0 : 1)) + 1; + end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1; for (var j = start; j < end; ++j) - { indentLine(this$1, j, how); } - var newRanges = this$1.doc.sel.ranges; + { indentLine(this, j, how); } + var newRanges = this.doc.sel.ranges; if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0) - { replaceOneSelection(this$1.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); } - } else if (range$$1.head.line > end) { - indentLine(this$1, range$$1.head.line, how, true); - end = range$$1.head.line; - if (i == this$1.doc.sel.primIndex) { ensureCursorVisible(this$1); } + { replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); } + } else if (range.head.line > end) { + indentLine(this, range.head.line, how, true); + end = range.head.line; + if (i == this.doc.sel.primIndex) { ensureCursorVisible(this); } } } }), @@ -8334,8 +8333,6 @@ }, getHelpers: function(pos, type) { - var this$1 = this; - var found = []; if (!helpers.hasOwnProperty(type)) { return found } var help = helpers[type], mode = this.getModeAt(pos); @@ -8353,7 +8350,7 @@ } for (var i$1 = 0; i$1 < help._global.length; i$1++) { var cur = help._global[i$1]; - if (cur.pred(mode, this$1) && indexOf(found, cur.val) == -1) + if (cur.pred(mode, this) && indexOf(found, cur.val) == -1) { found.push(cur.val); } } return found @@ -8366,10 +8363,10 @@ }, cursorCoords: function(start, mode) { - var pos, range$$1 = this.doc.sel.primary(); - if (start == null) { pos = range$$1.head; } + var pos, range = this.doc.sel.primary(); + if (start == null) { pos = range.head; } else if (typeof start == "object") { pos = clipPos(this.doc, start); } - else { pos = start ? range$$1.from() : range$$1.to(); } + else { pos = start ? range.from() : range.to(); } return cursorCoords(this, pos, mode || "page") }, @@ -8453,13 +8450,11 @@ triggerElectric: methodOp(function(text) { triggerElectric(this, text); }), findPosH: function(from, amount, unit, visually) { - var this$1 = this; - var dir = 1; if (amount < 0) { dir = -1; amount = -amount; } var cur = clipPos(this.doc, from); for (var i = 0; i < amount; ++i) { - cur = findPosH(this$1.doc, cur, dir, unit, visually); + cur = findPosH(this.doc, cur, dir, unit, visually); if (cur.hitSide) { break } } return cur @@ -8468,11 +8463,11 @@ moveH: methodOp(function(dir, unit) { var this$1 = this; - this.extendSelectionsBy(function (range$$1) { - if (this$1.display.shift || this$1.doc.extend || range$$1.empty()) - { return findPosH(this$1.doc, range$$1.head, dir, unit, this$1.options.rtlMoveVisually) } + this.extendSelectionsBy(function (range) { + if (this$1.display.shift || this$1.doc.extend || range.empty()) + { return findPosH(this$1.doc, range.head, dir, unit, this$1.options.rtlMoveVisually) } else - { return dir < 0 ? range$$1.from() : range$$1.to() } + { return dir < 0 ? range.from() : range.to() } }, sel_move); }), @@ -8481,23 +8476,21 @@ if (sel.somethingSelected()) { doc.replaceSelection("", null, "+delete"); } else - { deleteNearSelection(this, function (range$$1) { - var other = findPosH(doc, range$$1.head, dir, unit, false); - return dir < 0 ? {from: other, to: range$$1.head} : {from: range$$1.head, to: other} + { deleteNearSelection(this, function (range) { + var other = findPosH(doc, range.head, dir, unit, false); + return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other} }); } }), findPosV: function(from, amount, unit, goalColumn) { - var this$1 = this; - var dir = 1, x = goalColumn; if (amount < 0) { dir = -1; amount = -amount; } var cur = clipPos(this.doc, from); for (var i = 0; i < amount; ++i) { - var coords = cursorCoords(this$1, cur, "div"); + var coords = cursorCoords(this, cur, "div"); if (x == null) { x = coords.left; } else { coords.left = x; } - cur = findPosV(this$1, coords, dir, unit); + cur = findPosV(this, coords, dir, unit); if (cur.hitSide) { break } } return cur @@ -8508,14 +8501,14 @@ var doc = this.doc, goals = []; var collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected(); - doc.extendSelectionsBy(function (range$$1) { + doc.extendSelectionsBy(function (range) { if (collapse) - { return dir < 0 ? range$$1.from() : range$$1.to() } - var headPos = cursorCoords(this$1, range$$1.head, "div"); - if (range$$1.goalColumn != null) { headPos.left = range$$1.goalColumn; } + { return dir < 0 ? range.from() : range.to() } + var headPos = cursorCoords(this$1, range.head, "div"); + if (range.goalColumn != null) { headPos.left = range.goalColumn; } goals.push(headPos.left); var pos = findPosV(this$1, headPos, dir, unit); - if (unit == "page" && range$$1 == doc.sel.primary()) + if (unit == "page" && range == doc.sel.primary()) { addToScrollTop(this$1, charCoords(this$1, pos, "div").top - headPos.top); } return pos }, sel_move); @@ -8562,22 +8555,22 @@ clientHeight: displayHeight(this), clientWidth: displayWidth(this)} }, - scrollIntoView: methodOp(function(range$$1, margin) { - if (range$$1 == null) { - range$$1 = {from: this.doc.sel.primary().head, to: null}; + scrollIntoView: methodOp(function(range, margin) { + if (range == null) { + range = {from: this.doc.sel.primary().head, to: null}; if (margin == null) { margin = this.options.cursorScrollMargin; } - } else if (typeof range$$1 == "number") { - range$$1 = {from: Pos(range$$1, 0), to: null}; - } else if (range$$1.from == null) { - range$$1 = {from: range$$1, to: null}; + } else if (typeof range == "number") { + range = {from: Pos(range, 0), to: null}; + } else if (range.from == null) { + range = {from: range, to: null}; } - if (!range$$1.to) { range$$1.to = range$$1.from; } - range$$1.margin = margin || 0; + if (!range.to) { range.to = range.from; } + range.margin = margin || 0; - if (range$$1.from.line != null) { - scrollToRange(this, range$$1); + if (range.from.line != null) { + scrollToRange(this, range); } else { - scrollToCoordsRange(this, range$$1.from, range$$1.to, range$$1.margin); + scrollToCoordsRange(this, range.from, range.to, range.margin); } }), @@ -8588,11 +8581,11 @@ if (width != null) { this.display.wrapper.style.width = interpret(width); } if (height != null) { this.display.wrapper.style.height = interpret(height); } if (this.options.lineWrapping) { clearLineMeasurementCache(this); } - var lineNo$$1 = this.display.viewFrom; - this.doc.iter(lineNo$$1, this.display.viewTo, function (line) { + var lineNo = this.display.viewFrom; + this.doc.iter(lineNo, this.display.viewTo, function (line) { if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) - { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo$$1, "widget"); break } } } - ++lineNo$$1; + { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo, "widget"); break } } } + ++lineNo; }); this.curOp.forceUpdate = true; signal(this, "refresh", this); @@ -8609,7 +8602,7 @@ clearCaches(this); scrollToCoords(this, this.doc.scrollLeft, this.doc.scrollTop); updateGutterSpace(this.display); - if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5) + if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5 || this.options.lineWrapping) { estimateLineHeights(this); } signal(this, "refresh", this); }), @@ -8651,34 +8644,40 @@ } // Used for horizontal relative motion. Dir is -1 or 1 (left or - // right), unit can be "char", "column" (like char, but doesn't - // cross line boundaries), "word" (across next word), or "group" (to - // the start of next group of word or non-word-non-whitespace - // chars). The visually param controls whether, in right-to-left - // text, direction 1 means to move towards the next index in the - // string, or towards the character to the right of the current - // position. The resulting position will have a hitSide=true - // property if it reached the end of the document. + // right), unit can be "codepoint", "char", "column" (like char, but + // doesn't cross line boundaries), "word" (across next word), or + // "group" (to the start of next group of word or + // non-word-non-whitespace chars). The visually param controls + // whether, in right-to-left text, direction 1 means to move towards + // the next index in the string, or towards the character to the right + // of the current position. The resulting position will have a + // hitSide=true property if it reached the end of the document. function findPosH(doc, pos, dir, unit, visually) { var oldPos = pos; var origDir = dir; var lineObj = getLine(doc, pos.line); + var lineDir = visually && doc.direction == "rtl" ? -dir : dir; function findNextLine() { - var l = pos.line + dir; + var l = pos.line + lineDir; if (l < doc.first || l >= doc.first + doc.size) { return false } pos = new Pos(l, pos.ch, pos.sticky); return lineObj = getLine(doc, l) } function moveOnce(boundToLine) { var next; - if (visually) { + if (unit == "codepoint") { + var ch = lineObj.text.charCodeAt(pos.ch + (unit > 0 ? 0 : -1)); + if (isNaN(ch)) { next = null; } + else { next = new Pos(pos.line, Math.max(0, Math.min(lineObj.text.length, pos.ch + dir * (ch >= 0xD800 && ch < 0xDC00 ? 2 : 1))), + -dir); } + } else if (visually) { next = moveVisually(doc.cm, lineObj, pos, dir); } else { next = moveLogically(lineObj, pos, dir); } if (next == null) { if (!boundToLine && findNextLine()) - { pos = endOfLine(visually, doc.cm, lineObj, pos.line, dir); } + { pos = endOfLine(visually, doc.cm, lineObj, pos.line, lineDir); } else { return false } } else { @@ -8687,7 +8686,7 @@ return true } - if (unit == "char") { + if (unit == "char" || unit == "codepoint") { moveOnce(); } else if (unit == "column") { moveOnce(true); @@ -8757,8 +8756,16 @@ var div = input.div = display.lineDiv; disableBrowserMagic(div, cm.options.spellcheck, cm.options.autocorrect, cm.options.autocapitalize); + function belongsToInput(e) { + for (var t = e.target; t; t = t.parentNode) { + if (t == div) { return true } + if (/\bCodeMirror-(?:line)?widget\b/.test(t.className)) { break } + } + return false + } + on(div, "paste", function (e) { - if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return } + if (!belongsToInput(e) || signalDOMEvent(cm, e) || handlePaste(e, cm)) { return } // IE doesn't fire input events, so we schedule a read for the pasted content in this way if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20); } }); @@ -8783,7 +8790,7 @@ }); function onCopyCut(e) { - if (signalDOMEvent(cm, e)) { return } + if (!belongsToInput(e) || signalDOMEvent(cm, e)) { return } if (cm.somethingSelected()) { setLastCopied({lineWise: false, text: cm.getSelections()}); if (e.type == "cut") { cm.replaceSelection("", null, "cut"); } @@ -8825,9 +8832,18 @@ on(div, "cut", onCopyCut); }; + ContentEditableInput.prototype.screenReaderLabelChanged = function (label) { + // Label for screenreaders, accessibility + if(label) { + this.div.setAttribute('aria-label', label); + } else { + this.div.removeAttribute('aria-label'); + } + }; + ContentEditableInput.prototype.prepareSelection = function () { var result = prepareSelection(this.cm, false); - result.focus = this.cm.state.focused; + result.focus = document.activeElement == this.div; return result }; @@ -8863,8 +8879,8 @@ var end = to.line < cm.display.viewTo && posToDOM(cm, to); if (!end) { var measure = view[view.length - 1].measure; - var map$$1 = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map; - end = {node: map$$1[map$$1.length - 1], offset: map$$1[map$$1.length - 2] - map$$1[map$$1.length - 3]}; + var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map; + end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]}; } if (!start || !end) { @@ -8923,7 +8939,7 @@ ContentEditableInput.prototype.focus = function () { if (this.cm.options.readOnly != "nocursor") { - if (!this.selectionInEditor()) + if (!this.selectionInEditor() || document.activeElement != this.div) { this.showSelection(this.prepareSelection(), true); } this.div.focus(); } @@ -9153,11 +9169,11 @@ addText(cmText); return } - var markerID = node.getAttribute("cm-marker"), range$$1; + var markerID = node.getAttribute("cm-marker"), range; if (markerID) { var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID)); - if (found.length && (range$$1 = found[0].find(0))) - { addText(getBetween(cm.doc, range$$1.from, range$$1.to).join(lineSep)); } + if (found.length && (range = found[0].find(0))) + { addText(getBetween(cm.doc, range.from, range.to).join(lineSep)); } return } if (node.getAttribute("contenteditable") == "false") { return } @@ -9225,13 +9241,13 @@ function find(textNode, topNode, offset) { for (var i = -1; i < (maps ? maps.length : 0); i++) { - var map$$1 = i < 0 ? measure.map : maps[i]; - for (var j = 0; j < map$$1.length; j += 3) { - var curNode = map$$1[j + 2]; + var map = i < 0 ? measure.map : maps[i]; + for (var j = 0; j < map.length; j += 3) { + var curNode = map[j + 2]; if (curNode == textNode || curNode == topNode) { var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]); - var ch = map$$1[j] + offset; - if (offset < 0 || curNode != textNode) { ch = map$$1[j + (offset ? 1 : 0)]; } + var ch = map[j] + offset; + if (offset < 0 || curNode != textNode) { ch = map[j + (offset ? 1 : 0)]; } return Pos(line, ch) } } @@ -9365,6 +9381,15 @@ this.textarea = this.wrapper.firstChild; }; + TextareaInput.prototype.screenReaderLabelChanged = function (label) { + // Label for screenreaders, accessibility + if(label) { + this.textarea.setAttribute('aria-label', label); + } else { + this.textarea.removeAttribute('aria-label'); + } + }; + TextareaInput.prototype.prepareSelection = function () { // Redraw the selection and/or cursor var cm = this.cm, display = cm.display, doc = cm.doc; @@ -9605,6 +9630,7 @@ TextareaInput.prototype.readOnlyChanged = function (val) { if (!val) { this.reset(); } this.textarea.disabled = val == "nocursor"; + this.textarea.readOnly = !!val; }; TextareaInput.prototype.setUneditable = function () {}; @@ -9656,7 +9682,7 @@ textarea.style.display = ""; if (textarea.form) { off(textarea.form, "submit", save); - if (typeof textarea.form.submit == "function") + if (!options.leaveSubmitMethodAlone && typeof textarea.form.submit == "function") { textarea.form.submit = realSubmit; } } }; @@ -9755,7 +9781,7 @@ addLegacyProps(CodeMirror); - CodeMirror.version = "5.48.2"; + CodeMirror.version = "5.58.1"; return CodeMirror; diff --git a/scripts/codemirror/mode/apl/index.html b/scripts/codemirror/mode/apl/index.html index 56ab02f..81cef49 100644 --- a/scripts/codemirror/mode/apl/index.html +++ b/scripts/codemirror/mode/apl/index.html @@ -12,7 +12,7 @@ .CodeMirror { border: 2px inset #dee; }