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("" + cx.tagName + ">"); + if (inner && (!prefix || tagType == "close" && matches(inner, prefix, matchInMiddle))) + result.push("" + inner + ">"); } 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:
Key buffer:+Vim mode:The vim keybindings are enabled by including
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 @@keymap/vim.js
and setting the @@ -95,19 +96,22 @@ become a complete vim implementationVim Mode API @@ -69,7 +70,7 @@@@ -3517,6 +3551,41 @@ editor.setOption("extraKeys", { 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 aname
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 @@ simplytrue
), 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", { andCodeMirror.fold.xml
, for XML-style languages, andCodeMirror.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 + classCodeMirror-foldmarker
, or a DOM node.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 alintOnChange: false
option to disable that. + You can pass aselfContain: true
option to render the tooltip inside the editor instance. Depends onaddon/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 - setCodeMirror.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: ++
+ This addon also defines- +
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.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 A demo of the addon is available here. +column
in the case + when nowrapOn
pattern is found in the range. If set to + false allows line to overflow thecolumn
limit if no +wrapOn
pattern found. Defaults to true.+ 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. 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 beundefined
orfalse
. ++ 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 aline range
,params.line
andparams.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
, andtoString
. + 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. Returnscm.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 byfindKey
. + 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:
+ ++
+ +- placeholder addon: Remove arrow function that ended up in the code.
+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
andgN
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:
+ ++
+ +- show-hint addon: Fix a regression that broke completion picking. +
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, fixR
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:
+ ++
+ +- Add a
+className
option toaddLineWidget
.- foldcode addon: Allow fold widgets to be functions, to dynamically create fold markers.
+- New themes: ayu-dark and ayu-mirage.
+- Make Shift-Delete to cut work on Firefox.
+- closetag addon: Properly handle self-closing tags.
+- handlebars mode: Fix triple-brace support.
+- searchcursor addon: Support mathing
+$
in reverse regexp search.- panel addon: Don’t get confused by changing panel sizes.
+- javascript-hint addon: Complete variables defined in outer scopes.
+- sublime bindings: Make by-subword motion more consistent with Sublime Text.
+- julia mode: Don’t break on zero-prefixed integers.
+- elm mode: Sync with upstream version.
+- sql mode: Support Postgres-style backslash-escaped string literals.
+21-10-2019: Version 5.49.2:
+ ++
+ +- sublime bindings: Make
+selectNextOccurrence
stop doing something when all occurrences are selected.- continuecomment addon: Respect
+indentWithTabs
option.- foldgutter addon: Optimize by reusing DOM when possible.
+- markdown mode: Don’t reset inline styles at the start of a continued list item line.
+- clike mode: Add a configuration for Objective-C++.
+20-09-2019: Version 5.49.0:
+ ++
+ +- New themes: moxer, material-darker, material-palenight, material-ocean.
+- xml mode: Provide a more abstract way to query context, which other modes for XML-like languages can also implement.
+- octave mode: Don’t mark common punctuation as error.
+- clike mode: Support nested comments and properly indent lambdas in Kotlin.
+- foldgutter and annotatescrollbar addons: Optimize use of
+setTimeout
/clearTimeout
.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. ++ + + + 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: 'Sponsors
+These companies support development of this project:
+ +', 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; }