From 14d7274d417005fbce00f94c8e56a9568c7fb012 Mon Sep 17 00:00:00 2001 From: mrdrogdrog Date: Sat, 31 Oct 2020 21:56:54 +0100 Subject: [PATCH] Update/5.58.2 (#1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Wire up shift-delete to fire a cut event on Gecko Issue #6061 * [julia mode] Fix getting stuck on integers with leading zeroes Closes #6064 * [continuecomment addon] Continue comments when a newline is inserted before them Fix issue where lastIndexOff was accidentally passed a negative start position, which causes it to search from the end of the string. Closes #6065 * Adjust posFromMouse to handle arbitrary xRel field values Closes #6067 * [vim bindings] Skip folded code when moving with j/k * [elm mode] Sync with upstream implementation Modifies this module to reflect changes made to this mode found in https://github.com/elm/elm-lang.org/blob/master/editor/cm/mode/elm.js * [cypher mode] Added keywords for system commands Includes multi database and privilege management commands * Support functions as fold widget argument So that the widgets can be dynamic with regards to their content. Expand the fold demo with a JSON editor that shows the number of elements in folded regions. * [sql mode] Support backslash and escape constants in pgsql Add support for escape constant as mentioned here: https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-ESCAPE * [sql mode] Simplify patch 3e6aafd236ffe1ea Issue #6081 * Add a className option to addLineWidget Issue #5952 * [javascript-hint addon] Properly iterate over local scopes See https://discuss.codemirror.net/t/function-parameter-autocomplete/2240/1 * [sublime bindings] Make by-sub-word motion more conformant to Sublime Closes #6091 * [sublime bindings] Fix sub-word motion at start of word * Mark version 5.50.0 * [sublime bindings] Add shortcut Ctrl-K Ctrl-D: find_under_expand_skip * [soy mode] Add support for default param value * Fix indentation after a {literal{/literal} block. * Fix: Broken line widget removal Removal of line widgets is broken in 5.50.0 due to invalid classname check * [nsis mode] Add commands up to NSIS v3.05 * Restore indentation when closing an array or generator. * Mark version 5.50.2 * If valid and invalid files are drag n dropped, paste all valid files * [rust mode] Fixed type names in demo code * Fix broken link in manual The external link to the ternjs.net demo page returns a 404 error; this PR corrects it. * [elm mode] Remove tab character * [show-hint addon] Scroll initially selected hint into view See https://discuss.codemirror.net/t/show-selectedhint-in-very-long-list-of-hints/2255 * [real-world uses] Add Adnuntius * Make sure clearHistory clears all linked histories Closes #6108 * [vim] fix R key in visual mode * [vim] fix behavior of ' and ` marks * [vim] implement gi gI gJ * Make sure contextmenu event is also forwarded when fired on the input field Since Firefox, as of patch a21ea6f496f09d0, seems to fire it on the textarea. Closes #6116 * When direction=rtl, fix home/end and arrow motion across line boundaries Closes #6117 * Mark version 5.51.0 * Update CHANGELOG.md * Fix confused markup in releases.html * [javascript mode] Don't get confused by trailing commas in parentheses Closes #6120 * Fix bug in bidi algorithm Arabic numerals were ordered incorrectly in an rtl context. Issue #6117 * Make goLineStartSmart behave better in direction=rtl docs * [dart mode] Add "yield" keyword * [lint addon] Add theme class name to tooltips * [stylus mode] Don't match #-rgb colors before a dash character Closes #6132 * Fix missing clipPos calls in file drop code Closes #6127 * [lint addon] Allow appending the tooltip to the wrapper element The tooltip in the existing way append to the body. When applied the codemirror context inside a shadow root (custom element) this calls append the tooltip out of the root components. Thus, the user has to monkey patch the appendchild method to override the behavior. This change would allow the tooltip to render in its own context with the `selfContain` option. * Fix previous patch to get option from the parsed option object Issue #6135 * [soy mode] Remove templates property from state * Fix driver from only running vim tests. * Improve time complexity. * Clip negative scroll-to coordinates Closes #6139 * [Soy] Improve map, list, record and list comprehension highlighting * Add support for map, list and record types. * Add support for list, record and map literals. * Add support for list comprehension. * Better variable matching in list comprehension. * [tern addon] Allow appending the tooltip to the codemirror hint options container if exists The current implementation of tern.js is appending the tooltip to the body. When applied the codemirror context inside a shadow root, tooltips are falling out of the root component. This change would append the tooltip to the container of codemirror hint options if it has else it will default to document.body * Fixing blockquote end check * [sTeX mode] Ensured that tag does not clash with object prototype properties * [verilog] Support folding by indentation * Update to add mllike mode in release * Mark as version 5.49.4 * Mark version 5.52.0 * [protobuf mode] Enable brace folding * [markdown mode] DIsallow single dash for a setext header Closes #6129 * Fix lint warnings * Fix failing the test when the linter finds an issue Issue #6156 * [real world uses] Add clone-it.github.io Using CodeMirror as HTML & CSS editors. * Add plantuml language mode * Mark as version 5.49.5 * [twig mode] Replace confusing/broken code in demo * [javascript mode] Don't get confused by missing expression in statement conditions Issue #4386 * Fix DOM selection update in contenteditable mode when another window has focus Refine the check for whether the editor has focus to look at document.activeElement instead of state.focused. Issue #6167 * Make sure to set the DOM selection on ContentEditableInput.focus Issue #6167 * add missing CSS properties * [vim bindings] Disable autocorrect for prompt * [zenburn theme] Improve specificity of background selector Closes #6180 * Fix bug in viewport updating for content-sized editors Closes #6181 * Mark version 5.52.2 * [powershell mode] Don't highlight backslashes as errors * [dialog addon] Don't close dialogs when tab loses focus * [vim keymap] Fix EOL handling in visual mode. Vim's visual mode allows the cursor to be positioned over EOL. This change fixes a bug where that EOL behavior only worked when in visual block mode. * [vim keymap] Don't mark fat cursor over EOL. This fixes a bug where a mouse click to the right of a line results in the cursor apparently over EOL, even though it is actually positioned over line.length-1. Cursor position should display over EOL only in visual or insert modes. Insert mode is handled by default cursor behavior and visual mode is handled by the fake cursor, so we should remove the special cursor EOL handling here and just clip to show the cursor in the right place. * [runmode-stanadlone addon] Update with changes from runmode.js This PR updates the `runMode` function in runmode-standalone.js with 3 commits from [runmode.js](https://github.com/codemirror/CodeMirror/blob/master/addon/runmode/runmode.js): - https://github.com/codemirror/CodeMirror/commit/7e35f03ad1639d92735c8dee1e1b5c86a727c873 - https://github.com/codemirror/CodeMirror/commit/53bc4b1f54670c827662d5210a37b35e63a07c39 - https://github.com/codemirror/CodeMirror/commit/64113ec97bb73c2a740d42d56021acb01ce05a92 The first commit from runmode.js allows the `callback` in runMode to be a function, as mentioned in https://codemirror.net/demo/runmode.html and https://discuss.codemirror.net/t/runmode-standalone-callback/2357. The last two commits fixes a copy-and-paste bug from IE. * Add a screenReaderLabel option to set an aria-label on the editor * Remove leftover argument Issue #6197 * [merge addon] Compensate for editor top offset when aligning lines Closes #6202 * [hint] Nicer scrolling with non-standard padding The `scrollToActive` function used to have a `3px` offset hardcoded, which matches the default style (`padding: 2px; border-width: 1px;`). Custom values for these these style attributes would lead to a small visual bug. * [show-hint addon] don't close hints on backspace prematurely Currently, when a completion is triggered with part of the identifier already typed and backspace is hit, hints are immediately closed (when cursor is moved before the original position that completion was triggered for). After this change, they will be closed only when the entire identifier is erased (cursor is moved before the identifier start). * Add functions to vimAPI documentation * [julia mode] Fix infinite loop for mismatched brackets Closes #6213 * docs: Fix simple typo, compatiblity -> compatibility There is a small typo in addon/search/searchcursor.js, mode/python/python.js. Should read `compatibility` rather than `compatiblity`. * [show-hint] Scroll cursor into view after picking **Fixes a minor visual bug:** The picked hint might push the cursor out of the screen - this scrolls the cursor back into view. (Would normally happen after the next keypress.) * [JavaScript-Hint] Add options.additionalContext property names as hints ... if not hinting within 'context' * [sublime keymap] Add Ctrl-K Ctrl+1 fold all shortcut * Make refresh always re-estimate line heights when wrapping is on Closes #6228 * [emacs keymap] Allow fallthrough to the default keymap Closes #6231 * [rust] Add some keywords * doc update to clarify that negative lookbehind assertion for regex is not supported * [show-hint] Make linter happy * [wast] Add new wast mode (for WebAssembly disassembly) This adds support for WebAssembly text format, as used in the browser DevTools (Firefox, Edge and Chrome DevTools all the like). * Mark version 5.53.0 * [show-hint addon] Fix broken completion picking Closes #6239 * Mark version 5.53.2 * Don't handle key events for the wrong target Closes #6242 * Add SASS2CSS https://www.sass2css.online/ * [python mode] Somewhat improve handling of format specs in format strings Issue #6244 * Disable scroll-on-focus in drag focus kludge Since it causes jumps in the scroll position on Chrome. Closes #6246 * [vim bindings] Remove a duplicate entry in defaultExCommandMap * Disable scroll workaround in start-drag handler for Safari Issue #6246 * [javascript mode] Add support for private properties Issue #6249 * [javascript mode] Allow class fields in non-TS mode Closes #6249 * Don't mess with the selection when refocusing a text field Issue #6242 * [runmode standalone] Add support for globalThis We use the standalone mode in DevTools in a worker, where `window` does not exist. Instead, we can use `globalThis` which should be the corresponding global scope in all scenarios. For older browsers that do not support `globalThis`, we fallback to `window`. Relevant DevTools change: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2174418/1/front_end/third_party/codemirror/package/addon/runmode/runmode-standalone.js * Also ignore clipboard events inside widgets in contenteditable input mode Issue #6242 * [matchbrackets addon] Disable highlighting when the editor isn't focused Closes #6252 * [javascript operator] Properly implement optional chaining operator Closes #6255 * Increase size of scrollbar-hack gap Issue #6258 * Add a sponsors section to the website * [tcl mode] Add # as a lineComment * [dart mode] Add `late` and `required` keywords, `Null` and `Never` types * [mode/meta] Remove unwanted space in TiddlyWiki mode name * [runmode addon] Add support for lookahead Closes codemirror/google-modes#300 * [javascript mode] Fix a runaway regexp Issue #6273 * Proper escaping of \s See: https://lgtm.com/rules/1510624619946/ * [match-highlighter] Fix issue in highlighting non-alphanumeric tokens Closes #6279 * [vim] Allow Ex-Commands with non-word names * [soy mode] Fix bug with "map" in type name Co-authored-by: Axel Lewenhaupt * [gfm mode] add fencedCodeBlockDefaultMode option * Mark version 5.54.0 * Don't render zero-width joiners as a special character Since it'll often mess up emoji rendering Issue #4488 * [real-world uses] Add Adaface PairPro Adding Adaface PairPro (remote pair programming tool with code editor, compiler and video conference) for interviews. Added in alphabetical order. * [vim] Fix vim-mode-change event being signalled twice * [gfm mode] Allow forward slash in fenced code language * [loadmode addon] Support overriding script loading and filename computation Issue #6295 Issue #6294 * Remove trailing whitespace * [runmode-standalone addon] Fix interface mismatch in StringStream constructor Closes codemirror/google-modes#300 * [javascript mode] Only allow HTML-style comments at the start of line Closes #6305 * [javascript mode] Reduce start-of-line restriction to HTML close comment tokens Issue #6305 * [pascal mode] Add highlighting for comments with curly brackets See #5523 * [markdown mode] Change fencedCodeBlockDefaultMode to 'text/plain' instead of '' * [julia mode] Tweak indent method * Fix lint error * [wast mode] update to match latest WebAssembly specification Also shorten the regex for the keyword tokens a bit. * [wast mode] Support atomics from the Wasm Threads proposal This also adds more test coverage for not only the atomic memory instructions, but also the regular memory instructions. It also shortens the regex's for keyword and atom a bit. * [sql-hint addon] Autocomplete suggestion on _ $ and # for ODBC * [wast mode] Support WebAssembly tail-calls proposal This also adds more test coverage for all other control instructions, not just the new ones from the tail-calls proposal. * [real-world uses] Add Innovay Web Tools * [runmode addon] Reuse existing support code for standalone/node versions of runmode * [runmode.node addon] Export countColumn again * [runmode addon] Fix lint issues * [closetag addon] Make whenClosing/whenOpening properly default to true Closes #6322 * Mark version 5.55.0 * [wast mode] Rename atomic.notify and *.atomic.wait Refs: WebAssembly/threads#149 * [wast mode] Support some Wasm SIMD instructions These keywords can be found at https://github.com/WebAssembly/simd/blob/master/proposals/simd/BinarySIMD.md. * [wast mode] Add more SIMD instructions This adds all comparison (eq, ne, lt, gt, le, ge), and v8x16.shuffle and v8x16.swizzle. Full list of instructions found at: https://github.com/WebAssembly/simd/blob/master/proposals/simd/BinarySIMD.md The ordering in the test file follows this the ordering in the binary form. The regex ordering is more arbitrary due to grouping. * [wast mode] Add more SIMD instructions Some arithmetic instructions, had to shuffle the regex a bit so that we will attempt to match i8x16.add_saturate_s first before i8x16.add. Full list available at: https://github.com/WebAssembly/simd/blob/master/proposals/simd/BinarySIMD.md * [wast mode] More SIMD instructions f32x4 and f64x2 arithmetic instructions. Sorted test cases to match the order in https://github.com/WebAssembly/simd/blob/master/proposals/simd/BinarySIMD.md to make it easier to spot missing instructions. * [wast mode] Complete SIMD instructions This finished the set of SIMD instructions 178 of them in total, also sorted tests by their ordering in https://github.com/WebAssembly/simd/blob/master/proposals/simd/BinarySIMD.md. * [sas mode] Add missing keywords I've noticed these few are missing. All from PROC MIXED * [vim bindings] Document events fired by vim mode * Fix line-wise pasting on Chrome Windows Closes #6337 * [hardwrap addon] introduce forceBreak * [hardbreak addon] Adjust formatting Issue #6338 * Add support for import expressions. Committer: Axel Lewenhaupt * [soy mode] Support template type Co-authored-by: Axel Lewenhaupt * [soy mode] Add support for index in for loops - Fix variable scrope issue with list comprehensions. Co-authored-by: Axel Lewenhaupt * [sql-hint addon] Treat single quotes like double quotes when looking at tokens See https://discuss.codemirror.net/t/codemirror-ignore-show-hints-if-the-class-is-cm-string/2513 * Stop linking to the github wiki * [show-hint addon] Introduced option 'scrollMargin' * Mark version 5.56.0 * [vim bindings] Support tag text objects in xml / htmlmixed mode User can use `t` to operate on tag text objects. For example, given the following html: ```
hello world!
``` If the user's cursor (denoted by █) is inside "hello world!": ```
hello█world!
``` And they enter `dit` (delete inner tag), then the text inside the enclosing tag is deleted -- the following is the expected result: ```
``` If they enter `dat` (delete around tag), then the surrounding tags are deleted as well: ```
``` This logic depends on the following: - mode/xml/xml.js - addon/fold/xml-fold.js - editor is in htmlmixedmode / xml mode Caveats This is _NOT_ a 100% accurate implementation of vim tag text objects. For example, the following cases noop / are inconsistent with vim behavior: - Does not work inside comments: ``` ``` - Does not work when tags have different cases: ```
broken
``` - Does not work when inside a broken tag: ```
``` This addresses #3828. * Fix plantuml mode title * Add csv simple mode * Update links and meta * Fix MIME type * [real-world uses] Add CodeMirror-Record (#6360) * [real-world uses] Add Violentmonkey * [css] add missing 1) property all, 2) media feature prefers-color-scheme * [mode meta] Escape dot in mode's filename regex * [comment addon] Keep selection in front of closing marker when block-commenting ... with fullLines==false when the end of the selection is directly on the closing marker. Closes #6375 * [julia mode] Make sure dedent tokens end in a word boundary Closes #6376 * [css mode] Add missing standard property names per MDN * [css] missing CSS property values - for mask-image, mask-origin, touch-action just added * Mark as version 5.49.6 * Document the scrollpastend addon Closes #6381 * Add issue and pr templates that warn about common problems * Add graphviz simple mode * Mark as version 5.49.7 * Fix modeInfo might not be initialized first * Mark as version 5.49.8 * chore: update package namespace * [nsis mode] Add NSIS 3.06 commands * Annotate scrollbar when matches are folded * [annotatescrollbar addon] Simplify visual-line finding Issue #6388 * [xml-hint addon] Allow attribute values function to return a Promise * Check state.pending length * Fix csv regex undefined matching group Ref: https://github.com/codemirror/CodeMirror/issues/5374#issuecomment-384219584 * Fix state.pending might be empty array * Improve csv token colorization * Add warnings for now * Mark as version 5.49.9 * Recognise Cmd key in Firefox * Fix keyName function for Cmd key Corrects return value, expected "Mod" instead of "Cmd-Mod". * Mark version 5.57.0 * [real-world uses] Add Intervue * Upgrade markdown_math.js for 5.57.0 * Mark version 5.57.1 * chore: run build and release before publish instead of install * chore: run build and release before publish instead of install * Mark as version 5.57.2 * [ruby mode] Add keyword lists as a hintWords helper * [javascript mode] Improve handling of &&, ||, and ?? operators Closes #6394 * Don't default vim demo to contenteditable That option was apparently left over from a debugging session * [vim] Add black hole register * Add desmos sponsor link * Make backspace delete by codepoint Closes #6408 * Fix bug causing a deleted editor to continue believing it had focus Which kept the cursor blink and input poll intervals alive, leaking memory. Closes #6410 * Suppress focus outline for scrollbar elements Issue #6412 * Add vim emulation support for `gn` and `gN`. If we are given the following snippet of text: ``` A green green sky. _ ``` We can search for the word "green" with `/green`, and then use `gn` to select the next occurrence of "green" in visual mode. ``` A green green sky. ----- ``` Alternatively, we can use `cgn` and then enter the word "blue" to change the word "green" to "blue". ``` A blue green sky. ``` Then we can use the `.` operator to repeat the change: ``` A blue blue sky. ``` Addresses #3851. * Fix drawing of marked text with only attributes Closes #6414 * [lint addon] Use separate CSS classes for common lint styles This changes lint.css to be less reliant on the predefined severities (error and warning), in turn making it easier to define custom ones. Now all that needs to be done in order to define a new severity, e.g. `note`, is to add the following CSS: ```css /* underline */ .CodeMirror-lint-mark-note { background-image: ...; } /* icon */ .CodeMirror-lint-marker-note, .CodeMirror-lint-message-note { background-image: ...; } ``` Previously, it was necessary to copy many styles that were only available under the `CodeMirror-lint-*-error` and `CodeMirror-lint-*-warning` classes. * [lint addon] Put error CSS after warning By swapping the CSS rules, the error rules take priority in case there are markers with both severities on the same token. That token is now underlined red instead of yellow, making it consistent with how errors take priority in the gutter. * Set the readonly attribute on the hidden textarea when the editor is read-only This prevents cut/paste from showing up in the context menu on Chrome (but doesn't help on Firefox). Closes #6418 * Update placeholder visibility during composition Closes #6420: * Mark version 5.58.0 * Fix use of ES6 in addon * [placeholder addon] Fix composition handling Issue #6422 * Mark version 5.58.1 * [julia mode] Fix infinite recursion I couldn't figure out what the original code was intended to do, but I've tried to fix the problem without changing it more than necessary. Closes #6428 * Fixes #6331. Backticks are stripped from SQL query words before comparison * [tern demo] Use unpkg, now that the URL structure of ternjs.net changed * Remove link to gitter room It never took off, and I very much prefer communicating through the forum and bug tracker. * Fixes #6402. Adds option to turn off highlighting of non-standard CSS properties * Fix doc/releases.html copy-paste mistake * Support disableAutoIncrementMarkdownListNumbers option * Disable incrementRemainingMarkdownListNumbers * Fix bullet not assigned * Mark as version 5.57.3 * Fix horizontal scrolling-into-view with non-fixed gutters Closes #6436 * [javascript mode] Fix potentially-exponential regexp * [sparql mode] Improve parsing of IRI atoms * Do not treat the opening '<' of an expanded IRI atom as an operator The existing code would not highlight the IRI atom "" in the following line as an atom. FILTER( ?x = "42"^^ ) for example everything after the # would be highlighted as a comment. This is because the sequence "^^<" while all "operator characters", are not all SPARQL operators in this case: the "<" introduces the IRI atom. I special-case the "^^". * Improve PN_LOCAL parsing to SPARQL 1.1 The following legal sequences of characters from SPARQL 1.1 are additionally parsed as being the right-hand-side of a prefixed IRI. 1) Colons 2) PERCENT escaping 3) PN_LOCAL_ESCAPE escaping * [javascript mode] Don't indent in template strings Closes #6442 * [stylus mode] Recognize "url-prefix" token properly * Add WebAssembly to meta * Mark version 5.58.2 Co-authored-by: Marijn Haverbeke Co-authored-by: leaf Co-authored-by: T. Brandon Ashley Co-authored-by: Olivia Ytterbrink Co-authored-by: Opender Singh Co-authored-by: Aditya Toshniwal Co-authored-by: Axel Lewenhaupt Co-authored-by: Axel Lewenhaupt Co-authored-by: Hanno Fellmann Co-authored-by: Jan T. Sott Co-authored-by: elpnt <39664774+elpnt@users.noreply.github.com> Co-authored-by: James Cockshull Co-authored-by: antosarho Co-authored-by: nightwing Co-authored-by: David Rodrigues Co-authored-by: kvncp Co-authored-by: Roman Janusz Co-authored-by: Teja Co-authored-by: vamshi.revu Co-authored-by: Jay Contonio Co-authored-by: rvalavicius Co-authored-by: mtaran-google Co-authored-by: Max Wu Co-authored-by: Hein Htat Co-authored-by: Ilya Zverev Co-authored-by: Ilya Zverev Co-authored-by: clone-it <61330489+clone-it@users.noreply.github.com> Co-authored-by: Yukai Huang Co-authored-by: Patrick Kettner Co-authored-by: Erik Welander Co-authored-by: Matthew Casperson Co-authored-by: benhormann Co-authored-by: Alex Churchill Co-authored-by: BrianHung Co-authored-by: Aditya Toshniwal Co-authored-by: Fons van der Plas Co-authored-by: ianhi Co-authored-by: Tim Gates Co-authored-by: cBiscuit87 <36653704+cBiscuit87@users.noreply.github.com> Co-authored-by: Mélanie Chauvel Co-authored-by: Roberto Vidal Co-authored-by: d8888 Co-authored-by: Benedikt Meurer Co-authored-by: Dinindu D. Wanniarachchi <12568779+DininduWanniarachchi@users.noreply.github.com> Co-authored-by: John Chen Co-authored-by: Tim van der Lippe Co-authored-by: Peter László Co-authored-by: Sam Rawlins Co-authored-by: Boris K Co-authored-by: Ajin Abraham Co-authored-by: Jack Douglas Co-authored-by: Siddhartha Gunti Co-authored-by: ZeeshanNoor Co-authored-by: Ealton Co-authored-by: Ng Zhi An Co-authored-by: Paul Schmidt Co-authored-by: Kaushik Kulkarni Co-authored-by: Axel Lewenhaupt Co-authored-by: Bin Ni Co-authored-by: Howard Co-authored-by: Haoran Yu Co-authored-by: orionlee Co-authored-by: Lucas Buchala Co-authored-by: tokafew420 Co-authored-by: Leo Baschy Co-authored-by: Intervue <62877278+Intervue@users.noreply.github.com> Co-authored-by: Howard Jing Co-authored-by: Adrian Kunz Co-authored-by: Nina Pypchenko <22447785+nina-py@users.noreply.github.com> Co-authored-by: Mark Boyes Co-authored-by: tophf Co-authored-by: David R. Myers --- .github/ISSUE_TEMPLATE.md | 5 + .github/PULL_REQUEST_TEMPLATE.md | 5 + .gitignore | 4 + AUTHORS | 95 +++ CHANGELOG.md | 324 +++++++ README.md | 1 - addon/comment/comment.js | 4 +- addon/comment/continuecomment.js | 74 +- addon/dialog/dialog.css | 1 + addon/dialog/dialog.js | 4 +- addon/display/fullscreen.css | 2 +- addon/display/panel.js | 52 +- addon/display/placeholder.js | 16 +- addon/edit/closetag.js | 43 +- addon/edit/continuelist.js | 19 +- addon/edit/matchbrackets.js | 12 +- addon/fold/foldcode.js | 9 +- addon/fold/foldgutter.js | 33 +- addon/hint/css-hint.js | 12 +- addon/hint/javascript-hint.js | 7 +- addon/hint/show-hint.js | 65 +- addon/hint/sql-hint.js | 4 +- addon/hint/xml-hint.js | 40 +- addon/lint/lint.css | 24 +- addon/lint/lint.js | 37 +- addon/merge/merge.js | 18 +- addon/mode/loadmode.js | 22 +- addon/mode/simple.js | 4 +- addon/runmode/runmode-standalone.js | 158 ---- addon/runmode/runmode.js | 14 +- addon/runmode/runmode.node.js | 197 ----- addon/scroll/annotatescrollbar.js | 16 +- addon/scroll/simplescrollbars.css | 15 +- addon/search/match-highlighter.js | 4 +- addon/search/matchesonscrollbar.css | 3 +- addon/search/search.js | 6 +- addon/search/searchcursor.js | 35 +- addon/tern/tern.js | 11 +- addon/wrap/hardwrap.js | 30 +- demo/folding.html | 53 +- demo/runmode-standalone.html | 61 ++ demo/simplemode.html | 3 +- demo/tern.html | 20 +- demo/theme.html | 14 +- demo/vim.html | 10 +- doc/manual.html | 198 ++++- doc/realworld.html | 14 +- doc/releases.html | 214 +++++ index.html | 24 +- keymap/emacs.js | 4 +- keymap/sublime.js | 39 +- keymap/vim.js | 471 ++++++++--- lib/codemirror.css | 36 +- mode/apl/index.html | 2 +- mode/asciiarmor/index.html | 2 +- mode/asn.1/index.html | 2 +- mode/asterisk/asterisk.js | 28 +- mode/asterisk/index.html | 2 +- mode/brainfuck/index.html | 2 +- mode/clike/clike.js | 87 +- mode/clike/index.html | 2 +- mode/clike/scala.html | 2 +- mode/clike/test.js | 26 + mode/clojure/clojure.js | 2 +- mode/clojure/index.html | 2 +- mode/cmake/index.html | 2 +- mode/cobol/index.html | 2 +- mode/coffeescript/index.html | 2 +- mode/commonlisp/index.html | 2 +- mode/crystal/index.html | 2 +- mode/css/css.js | 219 ++--- mode/css/gss.html | 2 +- mode/css/index.html | 8 +- mode/css/less.html | 2 +- mode/css/scss.html | 2 +- mode/csv/csv.js | 29 + mode/csv/index.html | 48 ++ mode/cypher/cypher.js | 3 +- mode/cypher/index.html | 2 +- mode/d/index.html | 2 +- mode/dart/dart.js | 13 +- mode/dart/index.html | 2 +- mode/diff/index.html | 2 +- mode/django/index.html | 2 +- mode/dockerfile/index.html | 2 +- mode/dtd/index.html | 2 +- mode/dylan/index.html | 2 +- mode/ebnf/index.html | 2 +- mode/ecl/index.html | 2 +- mode/eiffel/index.html | 2 +- mode/elm/elm.js | 280 ++++--- mode/elm/index.html | 2 +- mode/erlang/index.html | 2 +- mode/factor/index.html | 2 +- mode/fcl/index.html | 2 +- mode/forth/index.html | 2 +- mode/fortran/index.html | 2 +- mode/gas/index.html | 2 +- mode/gfm/index.html | 2 +- mode/gherkin/index.html | 2 +- mode/go/index.html | 2 +- mode/graphviz/graphviz.js | 57 ++ mode/graphviz/index.html | 54 ++ mode/groovy/groovy.js | 5 +- mode/groovy/index.html | 2 +- mode/haml/index.html | 2 +- mode/handlebars/handlebars.js | 6 +- mode/handlebars/index.html | 4 +- mode/haskell/index.html | 2 +- mode/haxe/index.html | 2 +- mode/htmlembedded/index.html | 2 +- mode/htmlmixed/index.html | 2 +- mode/http/index.html | 2 +- mode/idl/index.html | 2 +- mode/index.html | 3 + mode/javascript/index.html | 2 +- mode/javascript/javascript.js | 50 +- mode/javascript/test.js | 27 + mode/javascript/typescript.html | 2 +- mode/jinja2/index.html | 2 +- mode/jsx/index.html | 2 +- mode/julia/index.html | 2 +- mode/julia/julia.js | 93 +-- mode/livescript/index.html | 2 +- mode/lua/index.html | 2 +- mode/markdown/index.html | 13 +- mode/markdown/markdown.js | 20 +- mode/markdown/markdown_math.js | 930 +++++++++++++++++++++ mode/markdown/test.js | 16 +- mode/mathematica/index.html | 2 +- mode/mbox/index.html | 2 +- mode/mediawiki/README.salvus | 16 + mode/mediawiki/img/black4.png | Bin 0 -> 87 bytes mode/mediawiki/img/ext2.png | Bin 0 -> 86 bytes mode/mediawiki/img/ext4.png | Bin 0 -> 86 bytes mode/mediawiki/img/link4.png | Bin 0 -> 86 bytes mode/mediawiki/img/template4.png | Bin 0 -> 86 bytes mode/mediawiki/img/template8.png | Bin 0 -> 86 bytes mode/mediawiki/mediawiki.css | 110 +++ mode/mediawiki/mediawiki.js | 791 ++++++++++++++++++ mode/meta.js | 22 +- mode/mirc/index.html | 2 +- mode/mllike/index.html | 2 +- mode/modelica/index.html | 2 +- mode/mscgen/index.html | 2 +- mode/mumps/index.html | 2 +- mode/nginx/index.html | 2 +- mode/nsis/index.html | 2 +- mode/nsis/nsis.js | 2 +- mode/ntriples/index.html | 2 +- mode/octave/index.html | 2 +- mode/octave/octave.js | 2 +- mode/oz/index.html | 2 +- mode/pascal/index.html | 2 +- mode/pascal/pascal.js | 17 +- mode/pegjs/index.html | 2 +- mode/perl/index.html | 2 +- mode/php/index.html | 2 +- mode/pig/index.html | 2 +- mode/plantuml/index.html | 58 ++ mode/plantuml/plantuml.js | 136 +++ mode/powershell/index.html | 6 +- mode/powershell/powershell.js | 2 +- mode/powershell/test.js | 2 +- mode/properties/index.html | 2 +- mode/protobuf/index.html | 2 +- mode/protobuf/protobuf.js | 5 +- mode/pug/index.html | 2 +- mode/pug/pug.js | 16 +- mode/puppet/index.html | 2 +- mode/python/index.html | 2 +- mode/python/python.js | 12 +- mode/q/index.html | 2 +- mode/r/index.html | 2 +- mode/rpm/index.html | 2 +- mode/rst/index.html | 2 +- mode/ruby/index.html | 2 +- mode/ruby/ruby.js | 48 +- mode/rust/index.html | 10 +- mode/rust/rust.js | 4 +- mode/sas/index.html | 2 +- mode/sas/sas.js | 2 +- mode/sass/index.html | 2 +- mode/scheme/index.html | 2 +- mode/shell/index.html | 2 +- mode/sieve/index.html | 2 +- mode/slim/index.html | 2 +- mode/smalltalk/index.html | 2 +- mode/smarty/index.html | 2 +- mode/solr/index.html | 2 +- mode/soy/index.html | 2 +- mode/soy/soy.js | 385 +++++++-- mode/soy/test.js | 132 ++- mode/sparql/index.html | 2 +- mode/sparql/sparql.js | 16 +- mode/spreadsheet/index.html | 2 +- mode/sql/index.html | 2 +- mode/sql/sql.js | 17 +- mode/stex/index.html | 2 +- mode/stex/stex.js | 2 +- mode/stylus/index.html | 2 +- mode/stylus/stylus.js | 5 +- mode/swift/index.html | 2 +- mode/tcl/index.html | 2 +- mode/tcl/tcl.js | 3 +- mode/textile/index.html | 2 +- mode/tiddlywiki/index.html | 2 +- mode/tiki/index.html | 2 +- mode/toml/index.html | 2 +- mode/tornado/index.html | 2 +- mode/troff/index.html | 2 +- mode/ttcn-cfg/index.html | 2 +- mode/ttcn/index.html | 2 +- mode/turtle/index.html | 2 +- mode/twig/index.html | 6 +- mode/typescript/typescript.js | 29 + mode/vb/index.html | 2 +- mode/vb/vb.js | 14 +- mode/vbscript/index.html | 2 +- mode/velocity/index.html | 2 +- mode/verilog/index.html | 2 +- mode/verilog/verilog.js | 3 +- mode/vhdl/index.html | 2 +- mode/vue/index.html | 2 +- mode/wast/index.html | 73 ++ mode/wast/test.js | 321 +++++++ mode/wast/wast.js | 41 + mode/xml/index.html | 2 +- mode/xml/xml.js | 11 + mode/xquery/index.html | 2 +- mode/yacas/index.html | 2 +- mode/yaml-frontmatter/index.html | 2 +- mode/yaml-frontmatter/yaml-frontmatter.js | 2 +- mode/yaml/index.html | 2 +- mode/z80/index.html | 2 +- package.json | 25 +- release | 6 + release.cmd | 75 ++ release.sh | 84 ++ rollup.config.js | 42 +- src/addon/runmode/codemirror-standalone.js | 22 + src/addon/runmode/codemirror.node.js | 21 + src/addon/runmode/runmode-standalone.js | 2 + src/addon/runmode/runmode.node.js | 2 + src/display/Display.js | 3 +- src/display/scrolling.js | 11 +- src/display/selection.js | 23 +- src/display/update_display.js | 5 +- src/display/update_line.js | 8 +- src/edit/CodeMirror.js | 9 +- src/edit/commands.js | 4 +- src/edit/drop_events.js | 41 +- src/edit/fromTextArea.js | 2 +- src/edit/key_events.js | 6 +- src/edit/main.js | 2 +- src/edit/methods.js | 32 +- src/edit/mouse_events.js | 6 +- src/edit/options.js | 8 +- src/input/ContentEditableInput.js | 25 +- src/input/TextareaInput.js | 14 +- src/input/input.js | 2 +- src/input/keymap.js | 2 +- src/input/keynames.js | 2 +- src/input/movement.js | 1 + src/line/highlight.js | 2 +- src/line/line_data.js | 2 +- src/measurement/position_measurement.js | 18 +- src/model/Doc.js | 5 +- src/model/changes.js | 5 +- src/model/history.js | 1 + src/model/selection_updates.js | 15 +- src/util/bidi.js | 5 +- src/util/misc.js | 26 +- test/annotatescrollbar.js | 55 ++ test/driver.js | 13 +- test/index.html | 29 +- test/lint.js | 2 +- test/phantom_driver.js | 31 - test/run.js | 40 +- test/search_test.js | 8 +- test/sublime_test.js | 19 +- test/test.js | 120 ++- test/vim_test.js | 591 +++++++++++-- theme/ayu-dark.css | 42 + theme/ayu-mirage.css | 43 + theme/darcula.css | 24 +- theme/material-darker.css | 135 +++ theme/material-ocean.css | 135 +++ theme/material-palenight.css | 135 +++ theme/material.css | 156 +++- theme/midnight.css | 4 - theme/moxer.css | 143 ++++ theme/one-dark.css | 221 +++++ theme/one-solarized.css | 214 +++++ theme/yonce.css | 4 +- theme/zenburn.css | 2 +- 296 files changed, 8175 insertions(+), 1717 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md delete mode 100644 addon/runmode/runmode-standalone.js delete mode 100644 addon/runmode/runmode.node.js create mode 100644 demo/runmode-standalone.html create mode 100644 mode/csv/csv.js create mode 100644 mode/csv/index.html create mode 100644 mode/graphviz/graphviz.js create mode 100644 mode/graphviz/index.html create mode 100644 mode/markdown/markdown_math.js create mode 100644 mode/mediawiki/README.salvus create mode 100644 mode/mediawiki/img/black4.png create mode 100644 mode/mediawiki/img/ext2.png create mode 100644 mode/mediawiki/img/ext4.png create mode 100644 mode/mediawiki/img/link4.png create mode 100644 mode/mediawiki/img/template4.png create mode 100644 mode/mediawiki/img/template8.png create mode 100644 mode/mediawiki/mediawiki.css create mode 100644 mode/mediawiki/mediawiki.js create mode 100644 mode/plantuml/index.html create mode 100644 mode/plantuml/plantuml.js create mode 100644 mode/typescript/typescript.js create mode 100644 mode/wast/index.html create mode 100644 mode/wast/test.js create mode 100644 mode/wast/wast.js create mode 100644 release create mode 100644 release.cmd create mode 100755 release.sh create mode 100644 src/addon/runmode/codemirror-standalone.js create mode 100644 src/addon/runmode/codemirror.node.js create mode 100644 src/addon/runmode/runmode-standalone.js create mode 100644 src/addon/runmode/runmode.node.js create mode 100644 test/annotatescrollbar.js delete mode 100644 test/phantom_driver.js create mode 100644 theme/ayu-dark.css create mode 100644 theme/ayu-mirage.css create mode 100644 theme/material-darker.css create mode 100644 theme/material-ocean.css create mode 100644 theme/material-palenight.css create mode 100644 theme/moxer.css create mode 100644 theme/one-dark.css create mode 100644 theme/one-solarized.css diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000000..49e2dcb09d --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..ea7cbc75db --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,5 @@ + diff --git a/.gitignore b/.gitignore index 1767b6d833..37d7294aa8 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,7 @@ .idea *.iml /lib/codemirror.js +codemirror.min.js +/addon/runmode/runmode-standalone.js +/addon/runmode/runmode.node.js +**/.DS_Store diff --git a/AUTHORS b/AUTHORS index a0db64dabb..b8087133a8 100644 --- a/AUTHORS +++ b/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,21 +124,26 @@ 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 +Bruno Logerfo +Bryan Gin-ge Chen Bryan Massoth Caitlin Potter Calin Barbat callodacity Camilo Roca Casey Klebba +cBiscuit87 César González Íñiguez Chad Jolly Chandra Sekhar Pydi @@ -156,6 +170,8 @@ Christopher Pfohl Christopher Wallis Chunliang Lyu ciaranj +clone-it +clso CodeAnimal CodeBitt coderaiser @@ -164,6 +180,7 @@ ComFreek Cristian Prieto Curran Kelleher Curtis Gagliardi +d8888 dagsta daines Dale Jung @@ -191,16 +208,21 @@ David Barnett David H. Bronke David Mignot David Pathakjee +David R. Myers +David Rodrigues David Santana David Vázquez David Whittington deebugger Deep Thought +Denis Ovsienko Devin Abbott Devon Carew Dick Choi +Diego Fernandez dignifiedquire Dimage Sapelkin +Dinindu D. Wanniarachchi dmaclach Dmitry Kiselyov domagoj412 @@ -213,18 +235,24 @@ Drew Hintz Drew Khoury Drini Cami Dror BG +Duncan Lilley duralog dwelle +Ealton eborden +edoroshenko edsharp ekhaled Elisée +elpnt Emmanuel Schanzer Enam Mijbah Noor Eric Allam Eric Bogard +Erik Demaine Erik Welander eustas +Evan Minsk Fabien Dubosson Fabien O'Carroll Fabio Zendhi Nagao @@ -241,11 +269,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 @@ -276,20 +306,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 @@ -298,21 +333,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 @@ -320,6 +363,7 @@ Jakob Miland Jakub Vrana Jakub Vrána James Campos +James Cockshull James Howard James Thorne Jamie Hill @@ -342,6 +386,7 @@ Jason Johnston Jason San Jose Jason Siefken Jayaprabhakar +Jay Contonio Jaydeep Solanki Jean Boussier Jeff Blaisdell @@ -361,10 +406,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 @@ -377,6 +425,7 @@ Jon Gacnik jongalloway Jon Malmaud Jon Sangster +Joo Joost-Wim Boekesteijn Joseph Pecoraro Josh Barnes @@ -399,8 +448,10 @@ jwallers@gmail.com kaniga karevn Karol +Kaushik Kulkarni Kayur Patel Kazuhito Hokamura +kcwiakala Kees de Kooter Kenan Christian Dimas Ken Newman @@ -420,6 +471,7 @@ koops Kris Ciccarello ks-ifware kubelsmieci +kvncp KwanEsq Kyle Kelley KyleMcNutt @@ -428,6 +480,7 @@ Lanfei Lanny laobubu Laszlo Vidacs +leaf leaf corcoran Lemmon Leo Baschy @@ -441,11 +494,14 @@ Lior Shub LloydMilligan LM lochel +Lonnie Abelbeck Lorenzo Simionato Lorenzo Stoakes Louis Mauchet Luca Fabbri +Lucas Buchala Luciano Longo +Luciano Santana Lu Fangjian Luke Browning Luke Granger-Brown @@ -469,7 +525,9 @@ Marijn Haverbeke Mário Gonçalves Mario Pietsch Mark Anderson +Mark Boyes Mark Dalgleish +Mark Hamstra Mark Lentczner Marko Bonaci Mark Peace @@ -488,11 +546,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 @@ -502,10 +562,12 @@ Maximilian Hils Maxim Kraev Max Kirsch Max Schaefer +Max Wu Max Xiantu mbarkhau McBrainy mce2 +Mélanie Chauvel melpon meshuamam Metatheos @@ -573,14 +635,22 @@ Nikita Vasilyev Nikolaj Kappler Nikolay Kostov nilp0inter +Nils Knappmeier +Nina Pypchenko 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 @@ -593,11 +663,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 @@ -608,6 +680,7 @@ peter Peter Flynn peterkroon Peter Kroon +Peter László Philipp A Philipp Markovics Philip Stadermann @@ -618,6 +691,7 @@ Pontus Melke prasanthj Prasanth J Prayag Verma +prendota Prendota Qiang Li Radek Piórkowski @@ -631,6 +705,7 @@ Randy Luecke Raphael Amorim Rasmus Erik Voel Jensen Rasmus Schultz +raymondf Raymond Hill ray ratchup Ray Ratchup @@ -646,10 +721,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 @@ -664,6 +743,7 @@ Sander Verweij santec Sarah McAlear and Wenlin Zhang Sascha Peilicke +Sasha Varlamov satamas satchmorun sathyamoorthi @@ -671,7 +751,9 @@ Saul Costa S. Chris Colbert SCLINIC\jdecker Scott Aikin +Scott Feeney Scott Goodhew +Seb35 Sebastian Wilzbach Sebastian Zaha Seren D @@ -689,6 +771,7 @@ Shiv Deepak Shmuel Englard Shubham Jain Siamak Mokhtari +Siddhartha Gunti silverwind Simon Edwards sinkuu @@ -710,6 +793,7 @@ Stephen Lavelle Steve Champagne Steve Hoover Steve O'Hara +stockiNail stoskov Stryder Crown Stu Kennedy @@ -721,7 +805,9 @@ Tako Schotanus Takuji Shimokawa Takuya Matsuyama Tarmil +T. Brandon Ashley TDaglis +Teja tel Tentone tfjgeorge @@ -737,13 +823,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 @@ -761,8 +850,11 @@ TSUYUSATO Kitsune Tugrul Elmas twifkak Tyler Long +Tyler Makaro +Vadim Dyachenko Vadzim Ramanenka Vaibhav Sagar +vamshi.revu VapidWorx Vestimir Markov vf @@ -786,6 +878,7 @@ Wojtek Ptak wonderboyjon Wu Cheng-Han Xavier Mendez +Yang Guo Yassin N. Hassan YNH Webdev yoongu @@ -794,8 +887,10 @@ Yuvi Panda Yvonnick Esnault Zac Anger Zachary Dremann +ZeeshanNoor Zeno Rocha Zhang Hao Ziv +zoobestik zziuni 魏鹏刚 diff --git a/CHANGELOG.md b/CHANGELOG.md index 970d857014..80200fc784 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,327 @@ +## 5.58.2 (2020-10-23) + +### Bug fixes + +Fix a bug where horizontally scrolling the cursor into view sometimes failed with a non-fixed gutter. + +[julia mode](https://codemirror.net/mode/julia/): Fix an infinite recursion bug. + +## 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
+
+[vim bindings](https://codemirror.net/demo/vim.html): Adjust char escape substitution to match vim, support `&/$0`.
+
+[search addon](https://codemirror.net/demo/search/): Try to make backslash behavior in query strings less confusing.
+
+[javascript mode](https://codemirror.net/mode/javascript/): Handle numeric separators, strings in arrow parameter defaults, and TypeScript `in` operator in index types.
+
+[sparql mode](https://codemirror.net/mode/sparql/index.html): Allow non-ASCII identifier characters.
+
+## 5.48.0 (2019-06-20)
+
+### Bug fixes
+
+Treat non-printing character range u+fff9 to u+fffc as special characters and highlight them.
+
+[show-hint addon](https://codemirror.net/doc/manual.html#addon_show-hint): Fix positioning when the dialog is placed in a scrollable container.
+
+### New features
+
+Add [`selectLeft`](https://codemirror.net/doc/manual.html#mark_selectLeft)/[`selectRight`](https://codemirror.net/doc/manual.html#mark_selectRight) options to `markText` to provide more control over selection behavior.
+
+## 5.47.0 (2019-05-21)
+
+### Bug fixes
+
+[python mode](https://codemirror.net/mode/python/): Properly handle `...` syntax.
+
+[ruby mode](https://codemirror.net/mode/ruby): Fix indenting before closing brackets.
+
+[vim bindings](https://codemirror.net/demo/vim.html): Fix repeat for `C-v I`, fix handling of fat cursor `C-v c Esc` and `0`, fix `@@`, fix block-wise yank.
+
+### New features
+
+[vim bindings](https://codemirror.net/demo/vim.html): Add support for `` ` `` text object.
+
+## 5.46.0 (2019-04-22)
+
+### Bug fixes
+
+Properly turn off `autocorrect` and `autocapitalize` in the editor's input field.
+
+Fix issue where calling [`swapDoc`](https://codemirror.net/doc/manual.html#swapDoc) during a mouse drag would cause an error.
+
+Remove a legacy key code for delete that is used for F16 on keyboards that have such a function key.
+
+[matchesonscrollbar addon](https://codemirror.net/doc/manual.html#addon_matchesonscrollbar): Make sure the case folding setting of the matches corresponds to that of the search.
+
+[swift mode](https://codemirror.net/mode/swift): Fix handling of empty strings.
+
+### New features
+
+Allow [gutters](https://codemirror.net/doc/manual.html#option_gutters) to specify direct CSS strings.
+
 ## 5.45.0 (2019-03-20)
 
 ### Bug fixes
diff --git a/README.md b/README.md
index 2a7b1f5eba..92debf4488 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,6 @@
 
 [![Build Status](https://travis-ci.org/codemirror/CodeMirror.svg)](https://travis-ci.org/codemirror/CodeMirror)
 [![NPM version](https://img.shields.io/npm/v/codemirror.svg)](https://www.npmjs.org/package/codemirror)
-[![Join the chat at https://gitter.im/codemirror/CodeMirror](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/codemirror/CodeMirror)  
 
 CodeMirror is a versatile text editor implemented in JavaScript for
 the browser. It is specialized for editing code, and comes with over
diff --git a/addon/comment/comment.js b/addon/comment/comment.js
index 8394e85a4d..dac48d0387 100644
--- a/addon/comment/comment.js
+++ b/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/addon/comment/continuecomment.js b/addon/comment/continuecomment.js
index a5f957b73b..7ca1b4a9cc 100644
--- a/addon/comment/continuecomment.js
+++ b/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/addon/dialog/dialog.css b/addon/dialog/dialog.css
index 677c078387..cf867fda28 100644
--- a/addon/dialog/dialog.css
+++ b/addon/dialog/dialog.css
@@ -29,4 +29,5 @@
 
 .CodeMirror-dialog button {
   font-size: 70%;
+  color: black;
 }
diff --git a/addon/dialog/dialog.js b/addon/dialog/dialog.js
index 23b06a8323..5f1f4aa4cc 100644
--- a/addon/dialog/dialog.js
+++ b/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/addon/display/fullscreen.css b/addon/display/fullscreen.css
index 437acd89be..e258ad6685 100644
--- a/addon/display/fullscreen.css
+++ b/addon/display/fullscreen.css
@@ -2,5 +2,5 @@
   position: fixed;
   top: 0; left: 0; right: 0; bottom: 0;
   height: auto;
-  z-index: 9;
+  z-index: 2000;
 }
diff --git a/addon/display/panel.js b/addon/display/panel.js
index 5faf1d560e..4c9f2c0fca 100644
--- a/addon/display/panel.js
+++ b/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++;
-    }
+
+    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)
+      this.scrollTo(null, this.getScrollInfo().top + height);
 
-    return new Panel(this, node, options, 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/addon/display/placeholder.js b/addon/display/placeholder.js
index 1a3fa33758..89bb93f378 100644
--- a/addon/display/placeholder.js
+++ b/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/addon/edit/closetag.js b/addon/edit/closetag.js
index e5e83bcd32..8689765eec 100644
--- a/addon/edit/closetag.js
+++ b/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/addon/edit/continuelist.js b/addon/edit/continuelist.js
index fb5f03735d..43d31e1cdd 100644
--- a/addon/edit/continuelist.js
+++ b/addon/edit/continuelist.js
@@ -11,8 +11,8 @@
 })(function(CodeMirror) {
   "use strict";
 
-  var listRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]\s|[*+-]\s|(\d+)([.)]))(\s*)/,
-      emptyListRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]|[*+-]|(\d+)[.)])(\s*)$/,
+  var listRE = /^(\s*)(>[> ]*|[*+-]\s|(\d+)([.)]))(\[\s\]\s|\[x\]\s|\s*)/,
+      emptyListRE = /^(\s*)(>[> ]*|[*+-]\s|(\d+)[.)])(\[\s\]\s*|\[x\]\s|\s*)$/,
       unorderedListRE = /[*+-]\s/;
 
   CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) {
@@ -41,19 +41,28 @@
         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
         });
         replacements[i] = "\n";
       } else {
+        var disableAutoIncrement = cm.getOption("disableAutoIncrementMarkdownListNumbers") || false
         var indent = match[1], after = match[5];
         var numbered = !(unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0);
-        var bullet = numbered ? (parseInt(match[3], 10) + 1) + match[4] : match[2].replace("x", " ");
+        var bullet
+        if (numbered) {
+          bullet = (disableAutoIncrement ? 1 : (parseInt(match[3], 10) + 1)) + match[4];
+        } else {
+          bullet = match[2].replace("x", " ");
+        }
+        after = after.replace('[x]', '[ ]'); // make todo list default unchecked
         replacements[i] = "\n" + indent + bullet + after;
 
-        if (numbered) incrementRemainingMarkdownListNumbers(cm, pos);
+        if (numbered && !disableAutoIncrement) incrementRemainingMarkdownListNumbers(cm, pos);
       }
     }
 
diff --git a/addon/edit/matchbrackets.js b/addon/edit/matchbrackets.js
index 2a147282c4..2c47e07033 100644
--- a/addon/edit/matchbrackets.js
+++ b/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/addon/fold/foldcode.js b/addon/fold/foldcode.js
index e146fb9f3e..887df3fe04 100644
--- a/addon/fold/foldcode.js
+++ b/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/addon/fold/foldgutter.js b/addon/fold/foldgutter.js
index 988c67c450..7d46a609b0 100644
--- a/addon/fold/foldgutter.js
+++ b/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/addon/hint/css-hint.js b/addon/hint/css-hint.js
index 6cdf728195..980d1197e5 100644
--- a/addon/hint/css-hint.js
+++ b/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/addon/hint/javascript-hint.js b/addon/hint/javascript-hint.js
index 96a7fe01c2..6d09e6b44e 100644
--- a/addon/hint/javascript-hint.js
+++ b/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/addon/hint/show-hint.js b/addon/hint/show-hint.js
index e3cd209d79..cd0d6a7bd5 100644
--- a/addon/hint/show-hint.js
+++ b/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 {
@@ -229,14 +239,26 @@
       elt.hintId = i;
     }
 
+    var container = completion.options.container || ownerDocument.body;
     var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null);
     var left = pos.left, top = pos.bottom, below = true;
-    hints.style.left = left + "px";
-    hints.style.top = top + "px";
+    var offsetLeft = 0, offsetTop = 0;
+    if (container !== ownerDocument.body) {
+      // We offset the cursor position because left and top are relative to the offsetParent's top left corner.
+      var isContainerPositioned = ['absolute', 'relative', 'fixed'].indexOf(parentWindow.getComputedStyle(container).position) !== -1;
+      var offsetParent = isContainerPositioned ? container : container.offsetParent;
+      var offsetParentPosition = offsetParent.getBoundingClientRect();
+      var bodyPosition = ownerDocument.body.getBoundingClientRect();
+      offsetLeft = (offsetParentPosition.left - bodyPosition.left - offsetParent.scrollLeft);
+      offsetTop = (offsetParentPosition.top - bodyPosition.top - offsetParent.scrollTop);
+    }
+    hints.style.left = (left - offsetLeft) + "px";
+    hints.style.top = (top - offsetTop) + "px";
+
     // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
     var winW = parentWindow.innerWidth || Math.max(ownerDocument.body.offsetWidth, ownerDocument.documentElement.offsetWidth);
     var winH = parentWindow.innerHeight || Math.max(ownerDocument.body.offsetHeight, ownerDocument.documentElement.offsetHeight);
-    (completion.options.container || ownerDocument.body).appendChild(hints);
+    container.appendChild(hints);
     var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH;
     var scrolls = hints.scrollHeight > hints.clientHeight + 1
     var startScroll = cm.getScrollInfo();
@@ -244,15 +266,15 @@
     if (overlapY > 0) {
       var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top);
       if (curTop - height > 0) { // Fits above cursor
-        hints.style.top = (top = pos.top - height) + "px";
+        hints.style.top = (top = pos.top - height - offsetTop) + "px";
         below = false;
       } else if (height > winH) {
         hints.style.height = (winH - 5) + "px";
-        hints.style.top = (top = pos.bottom - box.top) + "px";
+        hints.style.top = (top = pos.bottom - box.top - offsetTop) + "px";
         var cursor = cm.getCursor();
         if (data.from.ch != cursor.ch) {
           pos = cm.cursorCoords(cursor);
-          hints.style.left = (left = pos.left) + "px";
+          hints.style.left = (left = pos.left - offsetLeft) + "px";
           box = hints.getBoundingClientRect();
         }
       }
@@ -263,7 +285,7 @@
         hints.style.width = (winW - 5) + "px";
         overlapX -= (box.right - box.left) - winW;
       }
-      hints.style.left = (left = pos.left - overlapX) + "px";
+      hints.style.left = (left = pos.left - overlapX - offsetLeft) + "px";
     }
     if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling)
       node.style.paddingRight = cm.display.nativeBarWidth + "px"
@@ -310,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;
@@ -351,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/addon/hint/sql-hint.js b/addon/hint/sql-hint.js
index 444eba8b15..5b65e29105 100644
--- a/addon/hint/sql-hint.js
+++ b/addon/hint/sql-hint.js
@@ -187,7 +187,7 @@
   function eachWord(lineText, f) {
     var words = lineText.split(/\s+/)
     for (var i = 0; i < words.length; i++)
-      if (words[i]) f(words[i].replace(/[,;]/g, ''))
+      if (words[i]) f(words[i].replace(/[`,;]/g, ''))
   }
 
   function findTableByAlias(alias, editor) {
@@ -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/addon/hint/xml-hint.js b/addon/hint/xml-hint.js
index 106ba4f32c..543d19b61c 100644
--- a/addon/hint/xml-hint.js
+++ b/addon/hint/xml-hint.js
@@ -29,7 +29,7 @@
       token.string = token.string.slice(0, cur.ch - token.start);
     }
     var inner = CodeMirror.innerMode(cm.getMode(), token.state);
-    if (inner.mode.name != "xml") return;
+    if (!inner.mode.xmlCurrentTag) return
     var result = [], replaceToken = false, prefix;
     var tag = /\btag\b/.test(token.type) && !/>$/.test(token.string);
     var tagName = tag && /^\w/.test(token.string), tagStart;
@@ -44,12 +44,15 @@
       tagType = "close";
     }
 
-    if (!tag && !inner.state.tagName || tagType) {
+    var tagInfo = inner.mode.xmlCurrentTag(inner.state)
+    if (!tag && !tagInfo || tagType) {
       if (tagName)
         prefix = token.string;
       replaceToken = tagType;
-      var cx = inner.state.context, curTag = cx && tags[cx.tagName];
-      var childList = cx ? curTag && curTag.children : tags["!top"];
+      var context = inner.mode.xmlCurrentContext ? inner.mode.xmlCurrentContext(inner.state) : []
+      var inner = context.length && context[context.length - 1]
+      var curTag = inner && tags[inner]
+      var childList = inner ? curTag && curTag.children : tags["!top"];
       if (childList && tagType != "close") {
         for (var i = 0; i < childList.length; ++i) if (!prefix || matches(childList[i], prefix, matchInMiddle))
           result.push("<" + childList[i]);
@@ -58,11 +61,11 @@
           if (tags.hasOwnProperty(name) && name != "!top" && name != "!attrs" && (!prefix || matches(name, prefix, matchInMiddle)))
             result.push("<" + name);
       }
-      if (cx && (!prefix || tagType == "close" && matches(cx.tagName, prefix, matchInMiddle)))
-        result.push("");
+      if (inner && (!prefix || tagType == "close" && matches(inner, prefix, matchInMiddle)))
+        result.push("");
     } else {
       // Attribute completion
-      var curTag = tags[inner.state.tagName], attrs = curTag && curTag.attrs;
+      var curTag = tagInfo && tags[tagInfo.name], attrs = curTag && curTag.attrs;
       var globalAttrs = tags["!attrs"];
       if (!attrs && !globalAttrs) return;
       if (!attrs) {
@@ -98,8 +101,14 @@
           }
           replaceToken = true;
         }
-        for (var i = 0; i < atValues.length; ++i) if (!prefix || matches(atValues[i], prefix, matchInMiddle))
-          result.push(quote + atValues[i] + quote);
+        function returnHintsFromAtValues(atValues) {
+          if (atValues)
+            for (var i = 0; i < atValues.length; ++i) if (!prefix || matches(atValues[i], prefix, matchInMiddle))
+              result.push(quote + atValues[i] + quote);
+          return returnHints();
+        }
+        if (atValues && atValues.then) return atValues.then(returnHintsFromAtValues);
+        return returnHintsFromAtValues(atValues);
       } else { // An attribute name
         if (token.type == "attribute") {
           prefix = token.string;
@@ -109,11 +118,14 @@
           result.push(attr);
       }
     }
-    return {
-      list: result,
-      from: replaceToken ? Pos(cur.line, tagStart == null ? token.start : tagStart) : cur,
-      to: replaceToken ? Pos(cur.line, token.end) : cur
-    };
+    function returnHints() {
+      return {
+        list: result,
+        from: replaceToken ? Pos(cur.line, tagStart == null ? token.start : tagStart) : cur,
+        to: replaceToken ? Pos(cur.line, token.end) : cur
+      };
+    }
+    return returnHints();
   }
 
   CodeMirror.registerHelper("hint", "xml", getHints);
diff --git a/addon/lint/lint.css b/addon/lint/lint.css
index f097cfe345..0871865959 100644
--- a/addon/lint/lint.css
+++ b/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/addon/lint/lint.js b/addon/lint/lint.js
index aa75ba0e8a..963f2cf227 100644
--- a/addon/lint/lint.js
+++ b/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/addon/merge/merge.js b/addon/merge/merge.js
index 63373f75ed..827edb7133 100644
--- a/addon/merge/merge.js
+++ b/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);
     }
@@ -918,7 +922,7 @@
     hasMarker: function(n) {
       var handle = this.cm.getLineHandle(n)
       if (handle.markedSpans) for (var i = 0; i < handle.markedSpans.length; i++)
-        if (handle.markedSpans[i].mark.collapsed && handle.markedSpans[i].to != null)
+        if (handle.markedSpans[i].marker.collapsed && handle.markedSpans[i].to != null)
           return true
       return false
     },
diff --git a/addon/mode/loadmode.js b/addon/mode/loadmode.js
index 4ce716a012..fc695d0c37 100644
--- a/addon/mode/loadmode.js
+++ b/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/addon/mode/simple.js b/addon/mode/simple.js
index 655f991475..a1abf0910f 100644
--- a/addon/mode/simple.js
+++ b/addon/mode/simple.js
@@ -94,11 +94,13 @@
 
   function tokenFunction(states, config) {
     return function(stream, state) {
-      if (state.pending) {
+      if (state.pending && state.pending.length > 0) {
         var pend = state.pending.shift();
         if (state.pending.length == 0) state.pending = null;
         stream.pos += pend.text.length;
         return pend.token;
+      } else if (state.pending && state.pending.length === 0) {
+        console.warn('Regex capturing group is empty. Please check your regex')
       }
 
       if (state.local) {
diff --git a/addon/runmode/runmode-standalone.js b/addon/runmode/runmode-standalone.js
deleted file mode 100644
index 745eaf8440..0000000000
--- a/addon/runmode/runmode-standalone.js
+++ /dev/null
@@ -1,158 +0,0 @@
-// CodeMirror, copyright (c) by Marijn Haverbeke and others
-// Distributed under an MIT license: https://codemirror.net/LICENSE
-
-window.CodeMirror = {};
-
-(function() {
-"use strict";
-
-function splitLines(string){ return string.split(/\r?\n|\r/); };
-
-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() {
-    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() {return this.start - this.lineStart;},
-  indentation: function() {return 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() { return null }
-};
-CodeMirror.StringStream = StringStream;
-
-CodeMirror.startState = function (mode, a1, a2) {
-  return mode.startState ? mode.startState(a1, a2) : true;
-};
-
-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));
-      }
-    };
-  }
-
-  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;
-    }
-  }
-};
-})();
diff --git a/addon/runmode/runmode.js b/addon/runmode/runmode.js
index eb4cadf5b4..2cae68635d 100644
--- a/addon/runmode/runmode.js
+++ b/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/addon/runmode/runmode.node.js b/addon/runmode/runmode.node.js
deleted file mode 100644
index 53b6994c28..0000000000
--- a/addon/runmode/runmode.node.js
+++ /dev/null
@@ -1,197 +0,0 @@
-// CodeMirror, copyright (c) by Marijn Haverbeke and others
-// Distributed under an MIT license: https://codemirror.net/LICENSE
-
-/* Just enough of CodeMirror to run runMode under node.js */
-
-function splitLines(string){return string.split(/\r\n?|\n/);};
-
-// 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) {
-  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 StringStream(string, tabSize, context) {
-  this.pos = this.start = 0;
-  this.string = string;
-  this.tabSize = tabSize || 8;
-  this.lastColumnPos = this.lastColumnValue = 0;
-  this.lineStart = 0;
-  this.context = context
-};
-
-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;
-    }
-    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]
-  }
-};
-exports.StringStream = StringStream;
-
-exports.startState = function(mode, a1, a2) {
-  return mode.startState ? mode.startState(a1, a2) : true;
-};
-
-var modes = exports.modes = {}, mimeModes = exports.mimeModes = {};
-exports.defineMode = function(name, mode) {
-  if (arguments.length > 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");
-
-exports.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"};
-};
-
-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;
-}
-
-// 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);
-  var mfactory = modes[spec.name];
-  if (!mfactory) return exports.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 in spec.modeProps)
-    modeObj[prop] = spec.modeProps[prop];
-
-  return modeObj;
-};
-
-exports.innerMode = function(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};
-}
-
-exports.registerHelper = exports.registerGlobalHelper = Math.min;
-
-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);
-    while (!stream.eol()) {
-      var style = mode.token(stream, state);
-      callback(stream.current(), style, i, stream.start, state);
-      stream.start = stream.pos;
-    }
-  }
-};
-
-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/addon/scroll/annotatescrollbar.js b/addon/scroll/annotatescrollbar.js
index 356625811e..0f2f49eb7b 100644
--- a/addon/scroll/annotatescrollbar.js
+++ b/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))
@@ -101,7 +107,7 @@
       var height = Math.max(bottom - top, 3);
 
       var elt = frag.appendChild(document.createElement("div"));
-      elt.style.cssText = "position: absolute; right: 0px; width: " + Math.max(cm.display.barWidth - 1, 2) + "px; top: "
+      elt.style.cssText = "position: absolute; right: 0px; width: " + Math.max(cm.display.barWidth * 1.5, 2) + "px; top: "
         + (top + this.buttonHeight) + "px; height: " + height + "px";
       elt.className = this.options.className;
       if (ann.id) {
@@ -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/addon/scroll/simplescrollbars.css b/addon/scroll/simplescrollbars.css
index 5eea7aa1b3..3b75adc998 100644
--- a/addon/scroll/simplescrollbars.css
+++ b/addon/scroll/simplescrollbars.css
@@ -15,7 +15,7 @@
 
 .CodeMirror-simplescroll-horizontal {
   bottom: 0; left: 0;
-  height: 8px;
+  height: 6px;
 }
 .CodeMirror-simplescroll-horizontal div {
   bottom: 0;
@@ -24,7 +24,7 @@
 
 .CodeMirror-simplescroll-vertical {
   right: 0; top: 0;
-  width: 8px;
+  width: 6px;
 }
 .CodeMirror-simplescroll-vertical div {
   right: 0;
@@ -38,8 +38,9 @@
 
 .CodeMirror-overlayscroll-horizontal div, .CodeMirror-overlayscroll-vertical div {
   position: absolute;
-  background: #bcd;
-  border-radius: 3px;
+  background: #ccc;
+  border-radius: 7px;
+  border: 2px solid #222;
 }
 
 .CodeMirror-overlayscroll-horizontal, .CodeMirror-overlayscroll-vertical {
@@ -49,7 +50,7 @@
 
 .CodeMirror-overlayscroll-horizontal {
   bottom: 0; left: 0;
-  height: 6px;
+  height: 10px;
 }
 .CodeMirror-overlayscroll-horizontal div {
   bottom: 0;
@@ -57,8 +58,8 @@
 }
 
 .CodeMirror-overlayscroll-vertical {
-  right: 0; top: 0;
-  width: 6px;
+  right: 0px; top: 0px;
+  width: 10px;
 }
 .CodeMirror-overlayscroll-vertical div {
   right: 0;
diff --git a/addon/search/match-highlighter.js b/addon/search/match-highlighter.js
index b344ac79e2..3a4a7dedc1 100644
--- a/addon/search/match-highlighter.js
+++ b/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/addon/search/matchesonscrollbar.css b/addon/search/matchesonscrollbar.css
index 77932cc908..0ae3634295 100644
--- a/addon/search/matchesonscrollbar.css
+++ b/addon/search/matchesonscrollbar.css
@@ -1,7 +1,6 @@
 .CodeMirror-search-match {
   background: gold;
-  border-top: 1px solid orange;
-  border-bottom: 1px solid orange;
+  border: 1px solid orange;
   -moz-box-sizing: border-box;
   box-sizing: border-box;
   opacity: .5;
diff --git a/addon/search/search.js b/addon/search/search.js
index 5c2559c739..cecdd52ea1 100644
--- a/addon/search/search.js
+++ b/addon/search/search.js
@@ -78,10 +78,12 @@
   }
 
   function parseString(string) {
-    return string.replace(/\\(.)/g, function(_, ch) {
+    return string.replace(/\\([nrt\\])/g, function(match, ch) {
       if (ch == "n") return "\n"
       if (ch == "r") return "\r"
-      return ch
+      if (ch == "t") return "\t"
+      if (ch == "\\") return "\\"
+      return match
     })
   }
 
diff --git a/addon/search/searchcursor.js b/addon/search/searchcursor.js
index aae36dfe53..d586957887 100644
--- a/addon/search/searchcursor.js
+++ b/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/addon/tern/tern.js b/addon/tern/tern.js
index 253309d678..7be368188b 100644
--- a/addon/tern/tern.js
+++ b/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/addon/wrap/hardwrap.js b/addon/wrap/hardwrap.js
index 29cc15f01f..f194946c5d 100644
--- a/addon/wrap/hardwrap.js
+++ b/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/demo/folding.html b/demo/folding.html
index b61ecee122..166aa98cf9 100644
--- a/demo/folding.html
+++ b/demo/folding.html
@@ -53,7 +53,23 @@ 

Code Folding Demo

JavaScript:
HTML:
-
+ +
JSON with custom widget:
+
Python:

+ +

+
+    
+
+    

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

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

Simple Mode Demo

will be taken into account when matching the token. This regex has to capture groups when the token property is an array. If it captures groups, it must capture all of the string - (since JS provides no way to find out where a group matched). + (since JS provides no way to find out where a group matched). + Currently negative lookbehind assertion for regex is not supported, regardless of browser support.
token: string | array<string> | null
An optional token style. Multiple styles can be specified by separating them with dots or spaces. When this property holds an array of token styles, diff --git a/demo/tern.html b/demo/tern.html index c6834e8899..e331fd5cf8 100644 --- a/demo/tern.html +++ b/demo/tern.html @@ -13,16 +13,16 @@ - - - + + + - - - - - - + + + + + + @@ -109,7 +109,7 @@

Tern Demo

} var server; - getURL("//ternjs.net/defs/ecmascript.json", function(err, code) { + getURL("https://unpkg.com/tern/defs/ecmascript.json", function(err, code) { if (err) throw new Error("Request for ecmascript.json: " + err); server = new CodeMirror.TernServer({defs: [JSON.parse(code)]}); editor.setOption("extraKeys", { diff --git a/demo/theme.html b/demo/theme.html index 7bbc7a49e9..95d0f391fb 100644 --- a/demo/theme.html +++ b/demo/theme.html @@ -9,6 +9,8 @@ + + @@ -29,10 +31,14 @@ + + + + @@ -102,6 +108,8 @@

Theme Demo

+ + @@ -124,10 +132,14 @@

Theme Demo

+ + + + @@ -181,4 +193,4 @@

Theme Demo

if (theme) { input.value = theme; selectTheme(); } }); - + diff --git a/demo/vim.html b/demo/vim.html index c939505d8f..172ab6f04f 100644 --- a/demo/vim.html +++ b/demo/vim.html @@ -56,6 +56,7 @@

Vim bindings demo

}
Key buffer:
+
Vim mode:

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

Vim bindings demo

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/doc/manual.html b/doc/manual.html index 260b989ef8..1da41d3ccb 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -58,6 +58,7 @@
  • Vim Mode API
  • @@ -69,7 +70,7 @@

    User manual and reference guide - version 5.45.1 + version 5.58.2

    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 @@

    Configuration

    first mode that was loaded. It may be a string, which either simply names the mode or is a MIME type - associated with the mode. Alternatively, it may be an object - containing configuration options for the mode, with - a name property that names the mode (for + associated with the mode. The value "null" + indicates no highlighting should be applied. Alternatively, it + may be an object containing configuration options for the mode, + with a name property that names the mode (for example {name: "javascript", json: true}). The demo pages for each mode contain information about what configuration parameters the mode supports. You can ask CodeMirror which modes @@ -284,7 +286,7 @@

    Configuration

    should be replaced by a special placeholder. Mostly useful for non-printing special characters. The default - is /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/.
    + is /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff\ufff9-\ufffc]/.
    specialCharPlaceholder: function(char) → Element
    A function that, given a special character identified by the specialChars @@ -420,6 +422,10 @@

    Configuration

    simply true), focusing of the editor is also disallowed.
    +
    screenReaderLabel: string
    +
    This label is read by the screenreaders when CodeMirror text area is focused. This + is helpful for accessibility.
    +
    showCursorWhenSelecting: boolean
    Whether the cursor should be drawn when a selection is active. Defaults to false.
    @@ -557,13 +563,13 @@

    Configuration

    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.
    @@ -1674,13 +1680,21 @@

    Text-marking methods

    inclusiveRight: boolean
    Like inclusiveLeft, but for the right side.
    +
    selectLeft: boolean
    +
    For atomic ranges, determines whether the cursor is allowed + to be placed directly to the left of the range. Has no effect on + non-atomic ranges.
    +
    selectRight: boolean
    +
    Like selectLeft, + but for the right side.
    atomic: boolean
    Atomic ranges act as a single unit when cursor movement is concerned—i.e. it is impossible to place the cursor inside of - them. In atomic ranges, inclusiveLeft - and inclusiveRight have a different meaning—they - will prevent the cursor from being placed respectively - directly before and directly after the range.
    + them. You can control whether the cursor is allowed to be placed + directly before or after them using selectLeft + or selectRight. If selectLeft + (or right) is not provided, then inclusiveLeft (or + right) will control this behavior.
    collapsed: boolean
    Collapsed ranges do not show up in the display. Setting a range to be collapsed will automatically make it atomic.
    @@ -1872,6 +1886,9 @@

    Widget, gutter, and decoration methods

    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 @@ -2555,10 +2572,14 @@

    Addons

    and CodeMirror.fold.xml, for XML-style languages, and CodeMirror.fold.comment, for folding comment blocks. -
    widget: string|Element
    +
    widget: string | Element | fn(from: Pos, to: Pos) → string|Element
    The widget to show for folded ranges. Can be either a string, in which case it'll become a span with - class CodeMirror-foldmarker, or a DOM node.
    + class CodeMirror-foldmarker, or a DOM node. + To dynamically generate the widget, this can be a function + that returns a string or DOM node, which will then render + as described. The function will be invoked with parameters + identifying the range to be folded.
    scanUp: boolean
    When true (default is false), the addon will try to find foldable ranges on the lines above the current one if there @@ -2769,6 +2790,9 @@

    Addons

    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: @@ -2895,6 +2919,7 @@

    Addons

    will only be executed when the promise resolves. By default, the linter will run (debounced) whenever the document is changed. You can pass a lintOnChange: false option to disable that. + You can pass a selfContain: true option to render the tooltip inside the editor instance. Depends on addon/lint/lint.css. A demo can be found here. @@ -2929,13 +2954,20 @@

    Addons

    see a demo here.
    mode/loadmode.js
    -
    Defines a CodeMirror.requireMode(modename, - callback) function that will try to load a given mode and - call the callback when it succeeded. You'll have to - set CodeMirror.modeURL to a string that mode paths - can be constructed from, for - example "mode/%N/%N.js"—the %N's will - be replaced with the mode name. Also +
    Defines a CodeMirror.requireMode(modename, callback, + options) function that will try to load a given mode and + call the callback when it succeeded. options is an + optional object that may contain: +
    +
    path: fn(modeName: string) → string
    +
    Defines the way mode names are mapped to paths.
    +
    loadMode: fn(path: string, cont: fn())
    +
    Override the way the mode script is loaded. By default, + this will use the CommonJS or AMD module loader if one is + present, and fall back to creating + a <script> tag otherwise.
    +
    + This addon also defines CodeMirror.autoLoadMode(instance, mode), which will ensure the given mode is loaded and cause the given editor instance to refresh its mode when the loading @@ -3106,10 +3138,20 @@

    Addons

    killTrailingSpace: boolean
    Whether trailing space caused by wrapping should be preserved, or deleted. Defaults to true.
    +
    forceBreak: boolean
    +
    If set to true forces a break at column in the case + when no wrapOn pattern is found in the range. If set to + false allows line to overflow the column limit if no + wrapOn pattern found. Defaults to true.
    A demo of the addon is available here. +
    scroll/scrollpastend.js
    +
    Defines an option `"scrollPastEnd"` that, when set to a + truthy value, allows the user to scroll one editor height of + empty space into view at the bottom of the editor.
    +
    merge/merge.js
    Implements an interface for merging changes, using either a 2-way or a 3-way view. The CodeMirror.MergeView @@ -3162,14 +3204,14 @@

    Addons

    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.
    @@ -3509,6 +3551,41 @@

    Configuration

    extras.isEdit is applicable only to actions, determining whether it is recorded for replay for the . single-repeat command. + +
    unmap(lhs: string, ctx: string)
    +
    + Remove the command lhs if it is a user defined command. + If the command is an Ex to Ex or Ex to key mapping then the context + must be undefined or false. +
    + +
    mapclear(ctx: string)
    +
    + Remove all user-defined mappings for the provided context. +
    + +
    noremap(lhs: string, rhs: string, ctx: {string, array<string>})
    +
    + Non-recursive map function. This will not create mappings to key maps + that aren't present in the default key map. + If no context is provided then the mapping will be applied to each of + normal, insert, and visual mode. +
    + + +

    Events

    + +

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

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

    Extending VIM

    @@ -3574,7 +3651,74 @@

    Extending VIM

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

    CodeMirror real-world uses

    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 @@

      CodeMirror real-world uses

    • 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,14 +52,15 @@

      CodeMirror real-world uses

    • 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)
    • +
    • Coderba Google Web Toolkit (GWT) wrapper
    • Coderpad (interviewing tool)
    • 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)
    • @@ -76,6 +80,7 @@

      CodeMirror real-world uses

    • Eloquent JavaScript (book)
    • Emmet (fast XML editing)
    • Espruino Web IDE (Chrome App for writing code on Espruino devices)
    • +
    • EXLskills Live Interivews
    • Fastfig (online computation/math tool)
    • Farabi (modern Perl IDE)
    • FathomJS integration (slides with editors, again)
    • @@ -99,6 +104,8 @@

      CodeMirror real-world uses

    • 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)
    • @@ -118,6 +125,7 @@

      CodeMirror real-world uses

    • Kotlin (web-based mini-IDE for Kotlin)
    • Light Table (experimental IDE)
    • Liveweave (HTML/CSS/JS scratchpad)
    • +
    • LiveUML (PlantUML online editor)
    • Markdown Delight Editor (extensible markdown editor polymer component)
    • Marklight editor (lightweight markup editor)
    • Mergely (interactive diffing)
    • @@ -142,10 +150,12 @@

      CodeMirror real-world uses

    • Quantum (code editor for Chrome OS)
    • Qt+Webkit integration (building a desktop CodeMirror app)
    • Quivive File Manager
    • +
    • RackTables (data centre resources manager)
    • Rascal (tiny computer)
    • 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)
    • @@ -167,11 +177,13 @@

      CodeMirror real-world uses

    • 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/doc/releases.html b/doc/releases.html index 2bbe63240a..bdf24ed2f7 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -30,6 +30,220 @@

      Release notes and version history

      Version 5.x

      +

      23-10-2020: Version 5.58.2:

      + +
        +
      • Fix a bug where horizontally scrolling the cursor into view sometimes failed with a non-fixed gutter.
      • +
      • julia mode: Fix an infinite recursion bug.
      • +
      + +

      21-09-2020: Version 5.58.1:

      + + + +

      21-09-2020: Version 5.58.0:

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

      20-08-2020: Version 5.57.0:

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

      20-07-2020: Version 5.56.0:

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

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

      21-06-2020: Version 5.55.0:

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

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

      20-05-2020: Version 5.54.0:

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

      21-04-2020: Version 5.53.2:

      + + + +

      21-04-2020: Version 5.53.0:

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

      20-03-2020: Version 5.52.2:

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

      20-02-2020: Version 5.52.0:

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

      20-01-2020: Version 5.51.0:

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

      01-01-2020: Version 5.50.2:

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

      20-12-2019: Version 5.50.0:

      + + + +

      21-10-2019: Version 5.49.2:

      + + + +

      20-09-2019: Version 5.49.0:

      + + + +

      20-08-2019: Version 5.48.4:

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

      20-07-2019: Version 5.48.2:

      + +
        +
      • vim bindings: Adjust char escape substitution to match vim, support &/$0.
      • +
      • search addon: Try to make backslash behavior in query strings less confusing.
      • +
      • javascript mode: Handle numeric separators, strings in arrow parameter defaults, and TypeScript in operator in index types.
      • +
      • sparql mode: Allow non-ASCII identifier characters.
      • +
      + +

      20-06-2019: Version 5.48.0:

      + +
        +
      • Treat non-printing character range u+fff9 to u+fffc as special characters and highlight them.
      • +
      • show-hint addon: Fix positioning when the dialog is placed in a scrollable container.
      • +
      • Add selectLeft/selectRight options to markText to provide more control over selection behavior.
      • +
      + +

      21-05-2019: Version 5.47.0:

      + +
        +
      • python mode: Properly handle ... syntax.
      • +
      • ruby mode: Fix indenting before closing brackets.
      • +
      • vim bindings: Fix repeat for C-v I, fix handling of fat cursor C-v c Esc and 0, fix @@, fix block-wise yank.
      • +
      • vim bindings: Add support for ` text object.
      • +
      + +

      22-04-2019: Version 5.46.0:

      + +
        +
      • Allow gutters to specify direct CSS stings.
      • +
      • Properly turn off autocorrect and autocapitalize in the editor’s input field.
      • +
      • Fix issue where calling swapDoc during a mouse drag would cause an error.
      • +
      • Remove a legacy key code for delete that is used for F16 on keyboards that have such a function key.
      • +
      • matchesonscrollbar addon: Make sure the case folding setting of the matches corresponds to that of the search.
      • +
      • swift mode: Fix handling of empty strings.
      • +
      +

      20-03-2019: Version 5.45.0:

        diff --git a/index.html b/index.html index 1d45762a9f..6d41dcc79e 100644 --- a/index.html +++ b/index.html @@ -99,7 +99,7 @@

        This is CodeMirror

    - Get the current version: 5.45.0.
    + Get the current version: 5.58.2.
    You can see the code,
    read the release notes,
    or study the user manual. @@ -171,11 +171,6 @@

    Community

    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 @@

    Browser support

    pretty well.

    +
    + + +

    Sponsors

    +

    These companies support development of this project:

    + +
    + diff --git a/keymap/emacs.js b/keymap/emacs.js index d96a6fbec9..fe4882eb44 100644 --- a/keymap/emacs.js +++ b/keymap/emacs.js @@ -369,6 +369,7 @@ "Ctrl-/": repeated("undo"), "Shift-Ctrl--": repeated("undo"), "Ctrl-Z": repeated("undo"), "Cmd-Z": repeated("undo"), + "Shift-Ctrl-Z": "redo", "Shift-Alt-,": "goDocStart", "Shift-Alt-.": "goDocEnd", "Ctrl-S": "findPersistentNext", "Ctrl-R": "findPersistentPrev", "Ctrl-G": quit, "Shift-Alt-5": "replace", "Alt-/": "autocomplete", @@ -403,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/keymap/sublime.js b/keymap/sublime.js index 799641af20..7edf172eb5 100644 --- a/keymap/sublime.js +++ b/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/keymap/vim.js b/keymap/vim.js index 5758823867..111753dc58 100644 --- a/keymap/vim.js +++ b/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. @@ -44,6 +44,27 @@ })(function(CodeMirror) { 'use strict'; + // from https://hackernoon.com/copying-text-to-clipboard-with-javascript-df4d4988697f + function copyToClipboard (str) { + var el = document.createElement('textarea'); // Create a + + + +

    + Simple mode that handles CSV language. +

    + +

    MIME type defined: text/x-csv + (CSV) + diff --git a/mode/cypher/cypher.js b/mode/cypher/cypher.js index 8b22e65db8..aa76eb9e34 100644 --- a/mode/cypher/cypher.js +++ b/mode/cypher/cypher.js @@ -46,7 +46,7 @@ var word = stream.current(); if (funcs.test(word)) return "builtin"; if (preds.test(word)) return "def"; - if (keywords.test(word)) return "keyword"; + if (keywords.test(word) || systemKeywords.test(word)) return "keyword"; return "variable"; } }; @@ -67,6 +67,7 @@ var funcs = wordRegexp(["abs", "acos", "allShortestPaths", "asin", "atan", "atan2", "avg", "ceil", "coalesce", "collect", "cos", "cot", "count", "degrees", "e", "endnode", "exp", "extract", "filter", "floor", "haversin", "head", "id", "keys", "labels", "last", "left", "length", "log", "log10", "lower", "ltrim", "max", "min", "node", "nodes", "percentileCont", "percentileDisc", "pi", "radians", "rand", "range", "reduce", "rel", "relationship", "relationships", "replace", "reverse", "right", "round", "rtrim", "shortestPath", "sign", "sin", "size", "split", "sqrt", "startnode", "stdev", "stdevp", "str", "substring", "sum", "tail", "tan", "timestamp", "toFloat", "toInt", "toString", "trim", "type", "upper"]); var preds = wordRegexp(["all", "and", "any", "contains", "exists", "has", "in", "none", "not", "or", "single", "xor"]); var keywords = wordRegexp(["as", "asc", "ascending", "assert", "by", "case", "commit", "constraint", "create", "csv", "cypher", "delete", "desc", "descending", "detach", "distinct", "drop", "else", "end", "ends", "explain", "false", "fieldterminator", "foreach", "from", "headers", "in", "index", "is", "join", "limit", "load", "match", "merge", "null", "on", "optional", "order", "periodic", "profile", "remove", "return", "scan", "set", "skip", "start", "starts", "then", "true", "union", "unique", "unwind", "using", "when", "where", "with", "call", "yield"]); + var systemKeywords = wordRegexp(["access", "active", "assign", "all", "alter", "as", "catalog", "change", "copy", "create", "constraint", "constraints", "current", "database", "databases", "dbms", "default", "deny", "drop", "element", "elements", "exists", "from", "grant", "graph", "graphs", "if", "index", "indexes", "label", "labels", "management", "match", "name", "names", "new", "node", "nodes", "not", "of", "on", "or", "password", "populated", "privileges", "property", "read", "relationship", "relationships", "remove", "replace", "required", "revoke", "role", "roles", "set", "show", "start", "status", "stop", "suspended", "to", "traverse", "type", "types", "user", "users", "with", "write"]); var operatorChars = /[*+\-<>=&|~%^]/; return { diff --git a/mode/cypher/index.html b/mode/cypher/index.html index 0db7a6a7c6..43631d84df 100644 --- a/mode/cypher/index.html +++ b/mode/cypher/index.html @@ -16,7 +16,7 @@ }