upgrade to newest codemirror

pull/1/head
ansuz 9 years ago
parent 1a5905d9fd
commit 82a9b05d5f

@ -14,6 +14,7 @@ Ahmad Amireh
Ahmad M. Zawawi Ahmad M. Zawawi
ahoward ahoward
Akeksandr Motsjonov Akeksandr Motsjonov
Alasdair Smith
Alberto González Palomo Alberto González Palomo
Alberto Pose Alberto Pose
Albert Xing Albert Xing
@ -45,6 +46,7 @@ Andre von Houck
Andrey Fedorov Andrey Fedorov
Andrey Klyuchnikov Andrey Klyuchnikov
Andrey Lushnikov Andrey Lushnikov
Andrey Shchekin
Andy Joslin Andy Joslin
Andy Kimball Andy Kimball
Andy Li Andy Li
@ -75,9 +77,11 @@ benbro
Beni Cherniavsky-Paskin Beni Cherniavsky-Paskin
Benjamin DeCoste Benjamin DeCoste
Ben Keen Ben Keen
Ben Miller
Ben Mosher Ben Mosher
Bernhard Sirlinger Bernhard Sirlinger
Bert Chang Bert Chang
Bharad
Billy Moon Billy Moon
binny binny
B Krishna Chaitanya B Krishna Chaitanya
@ -94,6 +98,7 @@ Brian Sletten
Bruce Mitchener Bruce Mitchener
Caitlin Potter Caitlin Potter
Calin Barbat Calin Barbat
Camilo Roca
Chad Jolly Chad Jolly
Chandra Sekhar Pydi Chandra Sekhar Pydi
Charles Skelton Charles Skelton
@ -104,6 +109,7 @@ Chris Granger
Chris Houseknecht Chris Houseknecht
Chris Lohfink Chris Lohfink
Chris Morgan Chris Morgan
Chris Smith
Christian Oyarzun Christian Oyarzun
Christian Petrov Christian Petrov
Christopher Brown Christopher Brown
@ -135,6 +141,7 @@ Darius Roberts
Dave Brondsema Dave Brondsema
Dave Myers Dave Myers
David Barnett David Barnett
David H. Bronke
David Mignot David Mignot
David Pathakjee David Pathakjee
David Vázquez David Vázquez
@ -183,6 +190,7 @@ Gabriel Gheorghian
Gabriel Horner Gabriel Horner
Gabriel Nahmias Gabriel Nahmias
galambalazs galambalazs
Gary Sheng
Gautam Mehta Gautam Mehta
Gavin Douglas Gavin Douglas
gekkoe gekkoe
@ -199,6 +207,7 @@ Gordon Smith
Grant Skinner Grant Skinner
greengiant greengiant
Gregory Koberger Gregory Koberger
Grzegorz Mazur
Guillaume Massé Guillaume Massé
Guillaume Massé Guillaume Massé
guraga guraga
@ -206,6 +215,7 @@ Gustavo Rodrigues
Hakan Tunc Hakan Tunc
Hans Engel Hans Engel
Hardest Hardest
Harshvardhan Gupta
Hasan Karahan Hasan Karahan
Hector Oswaldo Caballero Hector Oswaldo Caballero
Herculano Campos Herculano Campos
@ -230,6 +240,7 @@ Jakob Miland
Jakub Vrana Jakub Vrana
Jakub Vrána Jakub Vrána
James Campos James Campos
James Howard
James Thorne James Thorne
Jamie Hill Jamie Hill
Jan Jongboom Jan Jongboom
@ -238,7 +249,9 @@ Jan Keromnes
Jan Odvarko Jan Odvarko
Jan Schär Jan Schär
Jan T. Sott Jan T. Sott
Jared Dean
Jared Forsyth Jared Forsyth
Jared Jacobs
Jason Jason
Jason Barnabe Jason Barnabe
Jason Grout Jason Grout
@ -248,6 +261,7 @@ Jason Siefken
Jaydeep Solanki Jaydeep Solanki
Jean Boussier Jean Boussier
Jeff Blaisdell Jeff Blaisdell
Jeff Jenkins
jeffkenton jeffkenton
Jeff Pickhardt Jeff Pickhardt
jem (graphite) jem (graphite)
@ -256,6 +270,7 @@ Jim
JobJob JobJob
jochenberger jochenberger
Jochen Berger Jochen Berger
joelpinheiro
Johan Ask Johan Ask
John Connor John Connor
John Engler John Engler
@ -271,6 +286,7 @@ Jon Sangster
Joost-Wim Boekesteijn Joost-Wim Boekesteijn
Joseph Pecoraro Joseph Pecoraro
Josh Cohen Josh Cohen
Josh Soref
Joshua Newman Joshua Newman
Josh Watzman Josh Watzman
jots jots
@ -297,6 +313,7 @@ Koh Zi Han, Cliff
komakino komakino
Konstantin Lopuhin Konstantin Lopuhin
koops koops
Kris Ciccarello
ks-ifware ks-ifware
kubelsmieci kubelsmieci
KwanEsq KwanEsq
@ -314,6 +331,7 @@ LM
lochel lochel
Lorenzo Stoakes Lorenzo Stoakes
Luciano Longo Luciano Longo
Lu Fangjian
Luke Stagner Luke Stagner
lynschinzer lynschinzer
M1cha M1cha
@ -321,6 +339,7 @@ Madhura Jayaratne
Maksim Lin Maksim Lin
Maksym Taran Maksym Taran
Malay Majithia Malay Majithia
Manideep
Manuel Rego Casasnovas Manuel Rego Casasnovas
Marat Dreizin Marat Dreizin
Marcel Gerber Marcel Gerber
@ -348,6 +367,7 @@ mats cronqvist
Matt Gaide Matt Gaide
Matthew Bauer Matthew Bauer
Matthew Beale Matthew Beale
matthewhayes
Matthew Rathbone Matthew Rathbone
Matthias Bussonnier Matthias Bussonnier
Matthias BUSSONNIER Matthias BUSSONNIER
@ -426,6 +446,7 @@ Paul Garvin
Paul Ivanov Paul Ivanov
Pavel Pavel
Pavel Feldman Pavel Feldman
Pavel Petržela
Pavel Strashkin Pavel Strashkin
Paweł Bartkiewicz Paweł Bartkiewicz
peteguhl peteguhl
@ -462,6 +483,7 @@ Ruslan Osmanov
Ryan Prior Ryan Prior
sabaca sabaca
Samuel Ainsworth Samuel Ainsworth
Sam Wilson
sandeepshetty sandeepshetty
Sander AKA Redsandro Sander AKA Redsandro
santec santec
@ -475,6 +497,7 @@ Scott Aikin
Scott Goodhew Scott Goodhew
Sebastian Zaha Sebastian Zaha
Sergey Goder Sergey Goder
Sergey Tselovalnikov
Se-Won Kim Se-Won Kim
shaund shaund
shaun gilchrist shaun gilchrist
@ -519,6 +542,7 @@ Thomas Schmid
Tim Alby Tim Alby
Tim Baumann Tim Baumann
Timothy Farrell Timothy Farrell
Timothy Gu
Timothy Hatcher Timothy Hatcher
TobiasBg TobiasBg
Tomas-A Tomas-A
@ -531,11 +555,13 @@ Triangle717
Tristan Tarrant Tristan Tarrant
TSUYUSATO Kitsune TSUYUSATO Kitsune
twifkak twifkak
VapidWorx
Vestimir Markov Vestimir Markov
vf vf
Victor Bocharsky Victor Bocharsky
Vincent Woo Vincent Woo
Volker Mische Volker Mische
Weiyan Shao
wenli wenli
Wes Cossick Wes Cossick
Wesley Wiser Wesley Wiser

@ -1,3 +1,95 @@
## 5.16.0 (2016-06-20)
### Bugfixes
Fix glitches when dragging content caused by the drop indicator receiving mouse events.
Make Control-drag work on Firefox.
Make clicking or selection-dragging at the end of a wrapped line select the right position.
[show-hint addon](http://codemirror.net/doc/manual.html#addon_show-hint): Prevent widget scrollbar from hiding part of the hint text.
[rulers addon](http://codemirror.net/doc/manual.html#addon_rulers): Prevent rulers from forcing a horizontal editor scrollbar.
### New features
[search addon](http://codemirror.net/doc/manual.html#addon_search): Automatically bind search-related keys in persistent dialog.
[sublime keymap](http://codemirror.net/demo/sublime.html): Add a multi-cursor aware smart backspace binding.
## 5.15.2 (2016-05-20)
### Bugfixes
Fix a critical document corruption bug that occurs when a document is gradually grown.
## 5.15.0 (2016-05-20)
### Bugfixes
Fix bug that caused the selection to reset when focusing the editor in contentEditable input mode.
Fix issue where not all ASCII control characters were being replaced by placeholders.
Remove the assumption that all modes have a `startState` method from several wrapping modes.
Fix issue where the editor would complain about overlapping collapsed ranges when there weren't any.
Optimize document tree building when loading or pasting huge chunks of content.
[markdown mode](http://codemirror.net/mode/markdown/): Fix several issues in matching link targets.
[clike mode](http://codemirror.net/mode/clike/): Improve indentation of C++ template declarations.
### New features
Explicitly bind Ctrl-O on OS X to make that binding (“open line”) act as expected.
Pasting [linewise-copied](http://codemirror.net/doc/manual.html#option_lineWiseCopyCut) content when there is no selection now inserts the lines above the current line.
[javascript mode](http://codemirror.net/mode/javascript/): Support `async`/`await` and improve support for TypeScript type syntax.
## 5.14.2 (2016-04-20)
### Bugfixes
Push a new package to NPM due to an [NPM bug](https://github.com/npm/npm/issues/5082) omitting the LICENSE file in 5.14.0.
Set `dataTransfer.effectAllowed` in `dragstart` handler to help browsers use the right drag icon.
Add the [mbox mode](http://codemirror.net/mode/mbox/index.html) to `mode/meta.js`.
## 5.14.0 (2016-04-20)
### Bugfixes
[`posFromIndex`](http://codemirror.net/doc/manual.html#posFromIndex) and [`indexFromPos`](http://codemirror.net/doc/manual.html#indexFromPos) now take [`lineSeparator`](http://codemirror.net/doc/manual.html#option_lineSeparator) into account.
[vim bindings](http://codemirror.net/demo/vim.html): Only call `.save()` when it is actually available.
[comment addon](http://codemirror.net/doc/manual.html#addon_comment): Be careful not to mangle multi-line strings.
[Python mode](http://codemirror.net/mode/python/index.html): Improve distinguishing of decorators from `@` operators.
[`findMarks`](http://codemirror.net/doc/manual.html#findMarks): No longer return marks that touch but don't overlap given range.
### New features
[vim bindings](http://codemirror.net/demo/vim.html): Add yank command.
[match-highlighter addon](http://codemirror.net/doc/manual.html#addon_match-highlighter): Add `trim` option to disable ignoring of whitespace.
[PowerShell mode](http://codemirror.net/mode/powershell/index.html): Added.
[Yacas mode](http://codemirror.net/mode/yacas/index.html): Added.
[Web IDL mode](http://codemirror.net/mode/webidl/index.html): Added.
[SAS mode](http://codemirror.net/mode/sas/index.html): Added.
[mbox mode](http://codemirror.net/mode/mbox/index.html): Added.
## 5.13.2 (2016-03-23) ## 5.13.2 (2016-03-23)
### Bugfixes ### Bugfixes

@ -44,9 +44,17 @@
} }
}); });
// Rough heuristic to try and detect lines that are part of multi-line string
function probablyInsideString(cm, pos, line) {
return /\bstring\b/.test(cm.getTokenTypeAt(Pos(pos.line, 0))) && !/^[\'\"`]/.test(line)
}
CodeMirror.defineExtension("lineComment", function(from, to, options) { CodeMirror.defineExtension("lineComment", function(from, to, options) {
if (!options) options = noOptions; if (!options) options = noOptions;
var self = this, mode = self.getModeAt(from); var self = this, mode = self.getModeAt(from);
var firstLine = self.getLine(from.line);
if (firstLine == null || probablyInsideString(self, from, firstLine)) return;
var commentString = options.lineComment || mode.lineComment; var commentString = options.lineComment || mode.lineComment;
if (!commentString) { if (!commentString) {
if (options.blockCommentStart || mode.blockCommentStart) { if (options.blockCommentStart || mode.blockCommentStart) {
@ -55,8 +63,7 @@
} }
return; return;
} }
var firstLine = self.getLine(from.line);
if (firstLine == null) return;
var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1); var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1);
var pad = options.padding == null ? " " : options.padding; var pad = options.padding == null ? " " : options.padding;
var blankLines = options.commentBlankLines || from.line == to.line; var blankLines = options.commentBlankLines || from.line == to.line;

@ -11,30 +11,26 @@
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.defineOption("rulers", false, function(cm, val, old) { CodeMirror.defineOption("rulers", false, function(cm, val) {
if (old && old != CodeMirror.Init) { if (cm.state.rulerDiv) {
clearRulers(cm); cm.display.lineSpace.removeChild(cm.state.rulerDiv)
cm.off("refresh", refreshRulers); cm.state.rulerDiv = null
cm.off("refresh", drawRulers)
} }
if (val && val.length) { if (val && val.length) {
setRulers(cm); cm.state.rulerDiv = cm.display.lineSpace.insertBefore(document.createElement("div"), cm.display.cursorDiv)
cm.on("refresh", refreshRulers); cm.state.rulerDiv.className = "CodeMirror-rulers"
drawRulers(cm)
cm.on("refresh", drawRulers)
} }
}); });
function clearRulers(cm) { function drawRulers(cm) {
for (var i = cm.display.lineSpace.childNodes.length - 1; i >= 0; i--) { cm.state.rulerDiv.textContent = ""
var node = cm.display.lineSpace.childNodes[i];
if (/(^|\s)CodeMirror-ruler($|\s)/.test(node.className))
node.parentNode.removeChild(node);
}
}
function setRulers(cm) {
var val = cm.getOption("rulers"); var val = cm.getOption("rulers");
var cw = cm.defaultCharWidth(); var cw = cm.defaultCharWidth();
var left = cm.charCoords(CodeMirror.Pos(cm.firstLine(), 0), "div").left; var left = cm.charCoords(CodeMirror.Pos(cm.firstLine(), 0), "div").left;
var minH = cm.display.scroller.offsetHeight + 30; cm.state.rulerDiv.style.minHeight = (cm.display.scroller.offsetHeight + 30) + "px";
for (var i = 0; i < val.length; i++) { for (var i = 0; i < val.length; i++) {
var elt = document.createElement("div"); var elt = document.createElement("div");
elt.className = "CodeMirror-ruler"; elt.className = "CodeMirror-ruler";
@ -49,15 +45,7 @@
if (conf.width) elt.style.borderLeftWidth = conf.width; if (conf.width) elt.style.borderLeftWidth = conf.width;
} }
elt.style.left = (left + col * cw) + "px"; elt.style.left = (left + col * cw) + "px";
elt.style.top = "-50px"; cm.state.rulerDiv.appendChild(elt)
elt.style.bottom = "-20px";
elt.style.minHeight = minH + "px";
cm.display.lineSpace.insertBefore(elt, cm.display.cursorDiv);
} }
} }
function refreshRulers(cm) {
clearRulers(cm);
setRulers(cm);
}
}); });

@ -109,7 +109,7 @@
var ranges = cm.listSelections(); var ranges = cm.listSelections();
var opening = pos % 2 == 0; var opening = pos % 2 == 0;
var type, next; var type;
for (var i = 0; i < ranges.length; i++) { for (var i = 0; i < ranges.length; i++) {
var range = ranges[i], cur = range.head, curType; var range = ranges[i], cur = range.head, curType;
var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1)); var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1));

@ -13,7 +13,7 @@
CodeMirror.registerHelper("fold", "brace", function(cm, start) { CodeMirror.registerHelper("fold", "brace", function(cm, start) {
var line = start.line, lineText = cm.getLine(line); var line = start.line, lineText = cm.getLine(line);
var startCh, tokenType; var tokenType;
function findOpening(openCh) { function findOpening(openCh) {
for (var at = start.ch, pass = 0;;) { for (var at = start.ch, pass = 0;;) {
@ -72,15 +72,15 @@ CodeMirror.registerHelper("fold", "import", function(cm, start) {
} }
} }
var start = start.line, has = hasImport(start), prev; var startLine = start.line, has = hasImport(startLine), prev;
if (!has || hasImport(start - 1) || ((prev = hasImport(start - 2)) && prev.end.line == start - 1)) if (!has || hasImport(startLine - 1) || ((prev = hasImport(startLine - 2)) && prev.end.line == startLine - 1))
return null; return null;
for (var end = has.end;;) { for (var end = has.end;;) {
var next = hasImport(end.line + 1); var next = hasImport(end.line + 1);
if (next == null) break; if (next == null) break;
end = next.end; end = next.end;
} }
return {from: cm.clipPos(CodeMirror.Pos(start, has.startCh + 1)), to: end}; return {from: cm.clipPos(CodeMirror.Pos(startLine, has.startCh + 1)), to: end};
}); });
CodeMirror.registerHelper("fold", "include", function(cm, start) { CodeMirror.registerHelper("fold", "include", function(cm, start) {
@ -91,14 +91,14 @@ CodeMirror.registerHelper("fold", "include", function(cm, start) {
if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8; if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8;
} }
var start = start.line, has = hasInclude(start); var startLine = start.line, has = hasInclude(startLine);
if (has == null || hasInclude(start - 1) != null) return null; if (has == null || hasInclude(startLine - 1) != null) return null;
for (var end = start;;) { for (var end = startLine;;) {
var next = hasInclude(end + 1); var next = hasInclude(end + 1);
if (next == null) break; if (next == null) break;
++end; ++end;
} }
return {from: CodeMirror.Pos(start, has + 1), return {from: CodeMirror.Pos(startLine, has + 1),
to: cm.clipPos(CodeMirror.Pos(end))}; to: cm.clipPos(CodeMirror.Pos(end))};
}); });

@ -29,7 +29,7 @@ CodeMirror.registerGlobalHelper("fold", "comment", function(mode) {
} }
if (pass == 1 && found < start.ch) return; if (pass == 1 && found < start.ch) return;
if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1))) && if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1))) &&
(lineText.slice(found - endToken.length, found) == endToken || (found == 0 || lineText.slice(found - endToken.length, found) == endToken ||
!/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found))))) { !/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found))))) {
startCh = found + startToken.length; startCh = found + startToken.length;
break; break;

@ -49,7 +49,7 @@
}); });
var myRange = cm.markText(range.from, range.to, { var myRange = cm.markText(range.from, range.to, {
replacedWith: myWidget, replacedWith: myWidget,
clearOnEnter: true, clearOnEnter: getOption(cm, options, "clearOnEnter"),
__isFold: true __isFold: true
}); });
myRange.on("clear", function(from, to) { myRange.on("clear", function(from, to) {
@ -129,7 +129,8 @@
rangeFinder: CodeMirror.fold.auto, rangeFinder: CodeMirror.fold.auto,
widget: "\u2194", widget: "\u2194",
minFoldSize: 0, minFoldSize: 0,
scanUp: false scanUp: false,
clearOnEnter: true
}; };
CodeMirror.defineOption("foldOptions", null); CodeMirror.defineOption("foldOptions", null);

@ -50,7 +50,7 @@
} }
function isFolded(cm, line) { function isFolded(cm, line) {
var marks = cm.findMarksAt(Pos(line)); var marks = cm.findMarks(Pos(line, 0), Pos(line + 1, 0));
for (var i = 0; i < marks.length; ++i) for (var i = 0; i < marks.length; ++i)
if (marks[i].__isFold && marks[i].find().from.line == line) return marks[i]; if (marks[i].__isFold && marks[i].find().from.line == line) return marks[i];
} }

@ -140,9 +140,9 @@
var openTag = toNextTag(iter), end; var openTag = toNextTag(iter), end;
if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return; if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return;
if (!openTag[1] && end != "selfClose") { if (!openTag[1] && end != "selfClose") {
var start = Pos(iter.line, iter.ch); var startPos = Pos(iter.line, iter.ch);
var close = findMatchingClose(iter, openTag[2]); var endPos = findMatchingClose(iter, openTag[2]);
return close && {from: start, to: close.from}; return endPos && {from: startPos, to: endPos.from};
} }
} }
}); });

@ -16,6 +16,7 @@
background: white; background: white;
font-size: 90%; font-size: 90%;
font-family: monospace; font-family: monospace;
max-width: 19em;
max-height: 20em; max-height: 20em;
overflow-y: auto; overflow-y: auto;
@ -25,8 +26,6 @@
margin: 0; margin: 0;
padding: 0 4px; padding: 0 4px;
border-radius: 2px; border-radius: 2px;
max-width: 19em;
overflow: hidden;
white-space: pre; white-space: pre;
color: black; color: black;
cursor: pointer; cursor: pointer;

@ -108,15 +108,11 @@
}, },
update: function(first) { update: function(first) {
if (this.tick == null) return; if (this.tick == null) return
if (!this.options.hint.async) { var self = this, myTick = ++this.tick
this.finishUpdate(this.options.hint(this.cm, this.options), first); fetchHints(this.options.hint, this.cm, this.options, function(data) {
} else { if (self.tick == myTick) self.finishUpdate(data, first)
var myTick = ++this.tick, self = this; })
this.options.hint(this.cm, function(data) {
if (self.tick == myTick) self.finishUpdate(data, first);
}, this.options);
}
}, },
finishUpdate: function(data, first) { finishUpdate: function(data, first) {
@ -233,6 +229,7 @@
var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight); var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
(completion.options.container || document.body).appendChild(hints); (completion.options.container || document.body).appendChild(hints);
var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH; var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH;
var scrolls = hints.scrollHeight > hints.clientHeight + 1
if (overlapY > 0) { if (overlapY > 0) {
var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top); var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top);
if (curTop - height > 0) { // Fits above cursor if (curTop - height > 0) { // Fits above cursor
@ -257,6 +254,8 @@
} }
hints.style.left = (left = pos.left - overlapX) + "px"; hints.style.left = (left = pos.left - overlapX) + "px";
} }
if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling)
node.style.paddingRight = cm.display.nativeBarWidth + "px"
cm.addKeyMap(this.keyMap = buildKeyMap(completion, { cm.addKeyMap(this.keyMap = buildKeyMap(completion, {
moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); }, moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); },
@ -362,40 +361,31 @@
return result return result
} }
function fetchHints(hint, cm, options, callback) {
if (hint.async) {
hint(cm, callback, options)
} else {
var result = hint(cm, options)
if (result && result.then) result.then(callback)
else callback(result)
}
}
function resolveAutoHints(cm, pos) { function resolveAutoHints(cm, pos) {
var helpers = cm.getHelpers(pos, "hint"), words var helpers = cm.getHelpers(pos, "hint"), words
if (helpers.length) { if (helpers.length) {
var async = false, resolved var resolved = function(cm, callback, options) {
for (var i = 0; i < helpers.length; i++) if (helpers[i].async) async = true var app = applicableHelpers(cm, helpers);
if (async) { function run(i) {
resolved = function(cm, callback, options) {
var app = applicableHelpers(cm, helpers)
function run(i, result) {
if (i == app.length) return callback(null) if (i == app.length) return callback(null)
var helper = app[i] fetchHints(app[i], cm, options, function(result) {
if (helper.async) { if (result && result.list.length > 0) callback(result)
helper(cm, function(result) {
if (result) callback(result)
else run(i + 1) else run(i + 1)
}, options) })
} else {
var result = helper(cm, options)
if (result) callback(result)
else run(i + 1)
}
} }
run(0) run(0)
} }
resolved.async = true resolved.async = true
} else {
resolved = function(cm, options) {
var app = applicableHelpers(cm, helpers)
for (var i = 0; i < app.length; i++) {
var cur = app[i](cm, options)
if (cur && cur.list.length) return cur
}
}
}
resolved.supportsSelection = true resolved.supportsSelection = true
return resolved return resolved
} else if (words = cm.getHelper(cm.getCursor(), "hintWords")) { } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) {

@ -18,7 +18,7 @@
QUERY_DIV: ";", QUERY_DIV: ";",
ALIAS_KEYWORD: "AS" ALIAS_KEYWORD: "AS"
}; };
var Pos = CodeMirror.Pos; var Pos = CodeMirror.Pos, cmpPos = CodeMirror.cmpPos;
function isArray(val) { return Object.prototype.toString.call(val) == "[object Array]" } function isArray(val) { return Object.prototype.toString.call(val) == "[object Array]" }
@ -105,7 +105,7 @@
} }
function nameCompletion(cur, token, result, editor) { function nameCompletion(cur, token, result, editor) {
// Try to complete table, colunm names and return start position of completion // Try to complete table, column names and return start position of completion
var useBacktick = false; var useBacktick = false;
var nameParts = []; var nameParts = [];
var start = token.start; var start = token.start;
@ -178,15 +178,6 @@
} }
} }
function convertCurToNumber(cur) {
// max characters of a line is 999,999.
return cur.line + cur.ch / Math.pow(10, 6);
}
function convertNumberToCur(num) {
return Pos(Math.floor(num), +num.toString().split('.').pop());
}
function findTableByAlias(alias, editor) { function findTableByAlias(alias, editor) {
var doc = editor.doc; var doc = editor.doc;
var fullQuery = doc.getValue(); var fullQuery = doc.getValue();
@ -209,15 +200,14 @@
separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length)); separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length));
//find valid range //find valid range
var prevItem = 0; var prevItem = null;
var current = convertCurToNumber(editor.getCursor()); var current = editor.getCursor()
for (var i = 0; i < separator.length; i++) { for (var i = 0; i < separator.length; i++) {
var _v = convertCurToNumber(separator[i]); if ((prevItem == null || cmpPos(current, prevItem) > 0) && cmpPos(current, separator[i]) <= 0) {
if (current > prevItem && current <= _v) { validRange = {start: prevItem, end: separator[i]};
validRange = { start: convertNumberToCur(prevItem), end: convertNumberToCur(_v) };
break; break;
} }
prevItem = _v; prevItem = separator[i];
} }
var query = doc.getRange(validRange.start, validRange.end, false); var query = doc.getRange(validRange.start, validRange.end, false);
@ -241,7 +231,7 @@
var defaultTableName = options && options.defaultTable; var defaultTableName = options && options.defaultTable;
var disableKeywords = options && options.disableKeywords; var disableKeywords = options && options.disableKeywords;
defaultTable = defaultTableName && getTable(defaultTableName); defaultTable = defaultTableName && getTable(defaultTableName);
keywords = keywords || getKeywords(editor); keywords = getKeywords(editor);
if (defaultTableName && !defaultTable) if (defaultTableName && !defaultTable)
defaultTable = findTableByAlias(defaultTableName, editor); defaultTable = findTableByAlias(defaultTableName, editor);

@ -4,10 +4,10 @@
} }
.CodeMirror-lint-tooltip { .CodeMirror-lint-tooltip {
background-color: infobackground; background-color: #ffd;
border: 1px solid black; border: 1px solid black;
border-radius: 4px 4px 4px 4px; border-radius: 4px 4px 4px 4px;
color: infotext; color: black;
font-family: monospace; font-family: monospace;
font-size: 10pt; font-size: 10pt;
overflow: hidden; overflow: hidden;

@ -204,7 +204,8 @@
var annotations = []; var annotations = [];
for (var i = 0; i < spans.length; ++i) { for (var i = 0; i < spans.length; ++i) {
annotations.push(spans[i].__annotation); var ann = spans[i].__annotation;
if (ann) annotations.push(ann);
} }
if (annotations.length) popupTooltips(annotations, e); if (annotations.length) popupTooltips(annotations, e);
} }

@ -40,7 +40,9 @@
if (cm.state.scrollPastEndPadding != padding) { if (cm.state.scrollPastEndPadding != padding) {
cm.state.scrollPastEndPadding = padding; cm.state.scrollPastEndPadding = padding;
cm.display.lineSpace.parentNode.style.paddingBottom = padding; cm.display.lineSpace.parentNode.style.paddingBottom = padding;
cm.off("refresh", updateBottomMargin);
cm.setSize(); cm.setSize();
cm.on("refresh", updateBottomMargin);
} }
} }
}); });

@ -59,10 +59,10 @@
CodeMirror.on(this.node, "DOMMouseScroll", onWheel); CodeMirror.on(this.node, "DOMMouseScroll", onWheel);
} }
Bar.prototype.setPos = function(pos) { Bar.prototype.setPos = function(pos, force) {
if (pos < 0) pos = 0; if (pos < 0) pos = 0;
if (pos > this.total - this.screen) pos = this.total - this.screen; if (pos > this.total - this.screen) pos = this.total - this.screen;
if (pos == this.pos) return false; if (!force && pos == this.pos) return false;
this.pos = pos; this.pos = pos;
this.inner.style[this.orientation == "horizontal" ? "left" : "top"] = this.inner.style[this.orientation == "horizontal" ? "left" : "top"] =
(pos * (this.size / this.total)) + "px"; (pos * (this.size / this.total)) + "px";
@ -76,9 +76,12 @@
var minButtonSize = 10; var minButtonSize = 10;
Bar.prototype.update = function(scrollSize, clientSize, barSize) { Bar.prototype.update = function(scrollSize, clientSize, barSize) {
var sizeChanged = this.screen != clientSize || this.total != scrollSize || this.size != barSize
if (sizeChanged) {
this.screen = clientSize; this.screen = clientSize;
this.total = scrollSize; this.total = scrollSize;
this.size = barSize; this.size = barSize;
}
var buttonSize = this.screen * (this.size / this.total); var buttonSize = this.screen * (this.size / this.total);
if (buttonSize < minButtonSize) { if (buttonSize < minButtonSize) {
@ -87,7 +90,7 @@
} }
this.inner.style[this.orientation == "horizontal" ? "width" : "height"] = this.inner.style[this.orientation == "horizontal" ? "width" : "height"] =
buttonSize + "px"; buttonSize + "px";
this.setPos(this.pos); this.setPos(this.pos, sizeChanged);
}; };
function SimpleScrollbars(cls, place, scroll) { function SimpleScrollbars(cls, place, scroll) {

@ -16,7 +16,7 @@
// highlighted only if the selected text is a word. showToken, when enabled, // highlighted only if the selected text is a word. showToken, when enabled,
// will cause the current token to be highlighted when nothing is selected. // will cause the current token to be highlighted when nothing is selected.
// delay is used to specify how much time to wait, in milliseconds, before // delay is used to specify how much time to wait, in milliseconds, before
// highlighting the matches. If annotateScrollbar is enabled, the occurances // highlighting the matches. If annotateScrollbar is enabled, the occurences
// will be highlighted on the scrollbar via the matchesonscrollbar addon. // will be highlighted on the scrollbar via the matchesonscrollbar addon.
(function(mod) { (function(mod) {
@ -29,24 +29,20 @@
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
var DEFAULT_MIN_CHARS = 2; var defaults = {
var DEFAULT_TOKEN_STYLE = "matchhighlight"; style: "matchhighlight",
var DEFAULT_DELAY = 100; minChars: 2,
var DEFAULT_WORDS_ONLY = false; delay: 100,
wordsOnly: false,
annotateScrollbar: false,
showToken: false,
trim: true
}
function State(options) { function State(options) {
if (typeof options == "object") { this.options = {}
this.minChars = options.minChars; for (var name in defaults)
this.style = options.style; this.options[name] = (options && options.hasOwnProperty(name) ? options : defaults)[name]
this.showToken = options.showToken;
this.delay = options.delay;
this.wordsOnly = options.wordsOnly;
this.annotateScrollbar = options.annotateScrollbar;
}
if (this.style == null) this.style = DEFAULT_TOKEN_STYLE;
if (this.minChars == null) this.minChars = DEFAULT_MIN_CHARS;
if (this.delay == null) this.delay = DEFAULT_DELAY;
if (this.wordsOnly == null) this.wordsOnly = DEFAULT_WORDS_ONLY;
this.overlay = this.timeout = null; this.overlay = this.timeout = null;
this.matchesonscroll = null; this.matchesonscroll = null;
} }
@ -68,13 +64,13 @@
function cursorActivity(cm) { function cursorActivity(cm) {
var state = cm.state.matchHighlighter; var state = cm.state.matchHighlighter;
clearTimeout(state.timeout); clearTimeout(state.timeout);
state.timeout = setTimeout(function() {highlightMatches(cm);}, state.delay); state.timeout = setTimeout(function() {highlightMatches(cm);}, state.options.delay);
} }
function addOverlay(cm, query, hasBoundary, style) { function addOverlay(cm, query, hasBoundary, style) {
var state = cm.state.matchHighlighter; var state = cm.state.matchHighlighter;
cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style)); cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style));
if (state.annotateScrollbar) { if (state.options.annotateScrollbar && cm.showMatchesOnScrollbar) {
var searchFor = hasBoundary ? new RegExp("\\b" + query + "\\b") : query; var searchFor = hasBoundary ? new RegExp("\\b" + query + "\\b") : query;
state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, true, state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, true,
{className: "CodeMirror-selection-highlight-scrollbar"}); {className: "CodeMirror-selection-highlight-scrollbar"});
@ -86,7 +82,7 @@
if (state.overlay) { if (state.overlay) {
cm.removeOverlay(state.overlay); cm.removeOverlay(state.overlay);
state.overlay = null; state.overlay = null;
if (state.annotateScrollbar) { if (state.matchesonscroll) {
state.matchesonscroll.clear(); state.matchesonscroll.clear();
state.matchesonscroll = null; state.matchesonscroll = null;
} }
@ -97,21 +93,22 @@
cm.operation(function() { cm.operation(function() {
var state = cm.state.matchHighlighter; var state = cm.state.matchHighlighter;
removeOverlay(cm); removeOverlay(cm);
if (!cm.somethingSelected() && state.showToken) { if (!cm.somethingSelected() && state.options.showToken) {
var re = state.showToken === true ? /[\w$]/ : state.showToken; var re = state.options.showToken === true ? /[\w$]/ : state.options.showToken;
var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start; var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start;
while (start && re.test(line.charAt(start - 1))) --start; while (start && re.test(line.charAt(start - 1))) --start;
while (end < line.length && re.test(line.charAt(end))) ++end; while (end < line.length && re.test(line.charAt(end))) ++end;
if (start < end) if (start < end)
addOverlay(cm, line.slice(start, end), re, state.style); addOverlay(cm, line.slice(start, end), re, state.options.style);
return; return;
} }
var from = cm.getCursor("from"), to = cm.getCursor("to"); var from = cm.getCursor("from"), to = cm.getCursor("to");
if (from.line != to.line) return; if (from.line != to.line) return;
if (state.wordsOnly && !isWord(cm, from, to)) return; if (state.options.wordsOnly && !isWord(cm, from, to)) return;
var selection = cm.getRange(from, to).replace(/^\s+|\s+$/g, ""); var selection = cm.getRange(from, to)
if (selection.length >= state.minChars) if (state.options.trim) selection = selection.replace(/^\s+|\s+$/g, "")
addOverlay(cm, selection, false, state.style); if (selection.length >= state.options.minChars)
addOverlay(cm, selection, false, state.options.style);
}); });
} }

@ -57,12 +57,13 @@
return cm.getSearchCursor(query, pos, queryCaseInsensitive(query)); return cm.getSearchCursor(query, pos, queryCaseInsensitive(query));
} }
function persistentDialog(cm, text, deflt, f) { function persistentDialog(cm, text, deflt, onEnter, onKeyDown) {
cm.openDialog(text, f, { cm.openDialog(text, onEnter, {
value: deflt, value: deflt,
selectValueOnOpen: true, selectValueOnOpen: true,
closeOnEnter: false, closeOnEnter: false,
onClose: function() { clearSearch(cm); } onClose: function() { clearSearch(cm); },
onKeyDown: onKeyDown
}); });
} }
@ -112,16 +113,19 @@
} }
} }
function doSearch(cm, rev, persistent) { function doSearch(cm, rev, persistent, immediate) {
var state = getSearchState(cm); var state = getSearchState(cm);
if (state.query) return findNext(cm, rev); if (state.query) return findNext(cm, rev);
var q = cm.getSelection() || state.lastQuery; var q = cm.getSelection() || state.lastQuery;
if (persistent && cm.openDialog) { if (persistent && cm.openDialog) {
var hiding = null var hiding = null
persistentDialog(cm, queryDialog, q, function(query, event) { var searchNext = function(query, event) {
CodeMirror.e_stop(event); CodeMirror.e_stop(event);
if (!query) return; if (!query) return;
if (query != state.queryText) startSearch(cm, state, query); if (query != state.queryText) {
startSearch(cm, state, query);
state.posFrom = state.posTo = cm.getCursor();
}
if (hiding) hiding.style.opacity = 1 if (hiding) hiding.style.opacity = 1
findNext(cm, event.shiftKey, function(_, to) { findNext(cm, event.shiftKey, function(_, to) {
var dialog var dialog
@ -130,7 +134,22 @@
dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top) dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top)
(hiding = dialog).style.opacity = .4 (hiding = dialog).style.opacity = .4
}) })
};
persistentDialog(cm, queryDialog, q, searchNext, function(event, query) {
var cmd = CodeMirror.keyMap[cm.getOption("keyMap")][CodeMirror.keyName(event)];
if (cmd == "findNext" || cmd == "findPrev") {
CodeMirror.e_stop(event);
startSearch(cm, getSearchState(cm), query);
cm.execCommand(cmd);
} else if (cmd == "find" || cmd == "findPersistent") {
CodeMirror.e_stop(event);
searchNext(query, event);
}
}); });
if (immediate) {
startSearch(cm, state, q);
findNext(cm, rev);
}
} else { } else {
dialog(cm, queryDialog, "Search for:", q, function(query) { dialog(cm, queryDialog, "Search for:", q, function(query) {
if (query && !state.query) cm.operation(function() { if (query && !state.query) cm.operation(function() {
@ -193,7 +212,7 @@
replaceAll(cm, query, text) replaceAll(cm, query, text)
} else { } else {
clearSearch(cm); clearSearch(cm);
var cursor = getSearchCursor(cm, query, cm.getCursor()); var cursor = getSearchCursor(cm, query, cm.getCursor("from"));
var advance = function() { var advance = function() {
var start = cursor.from(), match; var start = cursor.from(), match;
if (!(match = cursor.findNext())) { if (!(match = cursor.findNext())) {
@ -220,6 +239,8 @@
CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);}; CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);}; CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);};
CodeMirror.commands.findPersistentNext = function(cm) {doSearch(cm, false, true, true);};
CodeMirror.commands.findPersistentPrev = function(cm) {doSearch(cm, true, true, true);};
CodeMirror.commands.findNext = doSearch; CodeMirror.commands.findNext = doSearch;
CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);}; CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
CodeMirror.commands.clearSearch = clearSearch; CodeMirror.commands.clearSearch = clearSearch;

@ -179,7 +179,7 @@
var data = findDoc(ts, doc); var data = findDoc(ts, doc);
var argHints = ts.cachedArgHints; var argHints = ts.cachedArgHints;
if (argHints && argHints.doc == doc && cmpPos(argHints.start, change.to) <= 0) if (argHints && argHints.doc == doc && cmpPos(argHints.start, change.to) >= 0)
ts.cachedArgHints = null; ts.cachedArgHints = null;
var changed = data.changed; var changed = data.changed;
@ -306,7 +306,7 @@
ts.request(cm, {type: "type", preferFunction: true, end: start}, function(error, data) { ts.request(cm, {type: "type", preferFunction: true, end: start}, function(error, data) {
if (error || !data.type || !(/^fn\(/).test(data.type)) return; if (error || !data.type || !(/^fn\(/).test(data.type)) return;
ts.cachedArgHints = { ts.cachedArgHints = {
start: pos, start: start,
type: parseFnType(data.type), type: parseFnType(data.type),
name: data.exprName || data.name || "fn", name: data.exprName || data.name || "fn",
guess: data.guess, guess: data.guess,

@ -30,7 +30,9 @@
} }
function findBreakPoint(text, column, wrapOn, killTrailingSpace) { function findBreakPoint(text, column, wrapOn, killTrailingSpace) {
for (var at = column; at > 0; --at) 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 (wrapOn.test(text.slice(at - 1, at + 1))) break;
for (var first = true;; first = false) { for (var first = true;; first = false) {
var endOfText = at; var endOfText = at;

@ -18,7 +18,7 @@
// Script files are specified without .js ending. Prefixing them with // Script files are specified without .js ending. Prefixing them with
// their full (local) path is optional. So you may say lib/codemirror // their full (local) path is optional. So you may say lib/codemirror
// or mode/xml/xml to be more precise. In fact, even the .js suffix // or mode/xml/xml to be more precise. In fact, even the .js suffix
// may be speficied, if wanted. // may be specified, if wanted.
"use strict"; "use strict";
@ -68,7 +68,7 @@ walk("mode/");
if (!local && !blob) help(false); if (!local && !blob) help(false);
if (files.length) { if (files.length) {
console.log("Some speficied files were not found: " + console.log("Some specified files were not found: " +
files.map(function(a){return a.name;}).join(", ")); files.map(function(a){return a.name;}).join(", "));
process.exit(1); process.exit(1);
} }

@ -32,14 +32,12 @@ if (bumpOnly) process.exit(0);
child.exec("bash bin/authors.sh", function(){}); child.exec("bash bin/authors.sh", function(){});
var simple = number.slice(0, number.lastIndexOf("."));
rewrite("doc/compress.html", function(cmp) { rewrite("doc/compress.html", function(cmp) {
return cmp.replace(/<option value="http:\/\/codemirror.net\/">HEAD<\/option>/, return cmp.replace(/<option value="http:\/\/codemirror.net\/">HEAD<\/option>/,
"<option value=\"http://codemirror.net/\">HEAD</option>\n <option value=\"http://marijnhaverbeke.nl/git/codemirror?a=blob_plain;hb=" + number + ";f=\">" + simple + "</option>"); "<option value=\"http://codemirror.net/\">HEAD</option>\n <option value=\"http://marijnhaverbeke.nl/git/codemirror?a=blob_plain;hb=" + number + ";f=\">" + number + "</option>");
}); });
rewrite("index.html", function(index) { rewrite("index.html", function(index) {
return index.replace(/\.zip">\d+\.\d+<\/a>/, return index.replace(/\.zip">\d+\.\d+\.\d+<\/a>/,
".zip\">" + simple + "</a>"); ".zip\">" + number + "</a>");
}); });

@ -0,0 +1,35 @@
"use strict"
let version = process.argv[2]
let auth = process.argv[3]
if (!auth) {
console.log("Usage: upload-release.js [TAG] [github-user:password]")
process.exit(1)
}
require('child_process').exec("git --no-pager show -s --format='%s' " + version, (error, stdout) => {
if (error) throw error
let message = stdout.split("\n").slice(2)
message = message.slice(0, message.indexOf("-----BEGIN PGP SIGNATURE-----")).join("\n")
let req = require("https").request({
host: "api.github.com",
auth: auth,
headers: {"user-agent": "Release uploader"},
path: "/repos/codemirror/codemirror/releases",
method: "POST"
}, res => {
if (res.statusCode >= 300) {
console.error(res.statusMessage)
res.on("data", d => console.log(d.toString()))
res.on("end", process.exit(1))
}
})
req.write(JSON.stringify({
tag_name: version,
name: version,
body: message
}))
req.end()
})

@ -10,6 +10,7 @@
<script src="../addon/hint/show-hint.js"></script> <script src="../addon/hint/show-hint.js"></script>
<script src="../addon/hint/javascript-hint.js"></script> <script src="../addon/hint/javascript-hint.js"></script>
<script src="../mode/javascript/javascript.js"></script> <script src="../mode/javascript/javascript.js"></script>
<script src="../mode/markdown/markdown.js"></script>
<div id=nav> <div id=nav>
<a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../doc/logo.png"></a> <a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../doc/logo.png"></a>
@ -69,11 +70,57 @@ on top of the <a href="../doc/manual.html#addon_show-hint"><code>show-hint</code
and <a href="../doc/manual.html#addon_javascript-hint"><code>javascript-hint</code></a> and <a href="../doc/manual.html#addon_javascript-hint"><code>javascript-hint</code></a>
addons.</p> addons.</p>
<form><textarea style="display: none" id="synonyms" name="synonyms">
Here, the completion use an asynchronous hinting functions to provide
synonyms for each words. If your browser support `Promises`, the
hinting function can also return one.
</textarea></form>
<script> <script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), { var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true, lineNumbers: true,
extraKeys: {"Ctrl-Space": "autocomplete"}, extraKeys: {"Ctrl-Space": "autocomplete"},
mode: {name: "javascript", globalVars: true} mode: {name: "javascript", globalVars: true}
}); });
if (typeof Promise !== undefined) {
var comp = [
["here", "hither"],
["asynchronous", "nonsynchronous"],
["completion", "achievement", "conclusion", "culmination", "expirations"],
["hinting", "advive", "broach", "imply"],
["function","action"],
["provide", "add", "bring", "give"],
["synonyms", "equivalents"],
["words", "token"],
["each", "every"],
]
function synonyms(cm, option) {
return new Promise(function(accept) {
setTimeout(function() {
var cursor = cm.getCursor(), line = cm.getLine(cursor.line)
var start = cursor.ch, end = cursor.ch
while (start && /\w/.test(line.charAt(start - 1))) --start
while (end < line.length && /\w/.test(line.charAt(end))) ++end
var word = line.slice(start, end).toLowerCase()
for (var i = 0; i < comp.length; i++) if (comp[i].indexOf(word) != -1)
return accept({list: comp[i],
from: CodeMirror.Pos(cursor.line, start),
to: CodeMirror.Pos(cursor.line, end)})
return accept(null)
}, 100)
})
}
var editor2 = CodeMirror.fromTextArea(document.getElementById("synonyms"), {
extraKeys: {"Ctrl-Space": "autocomplete"},
lineNumbers: true,
lineWrapping: true,
mode: "text/x-markdown",
hintOptions: {hint: synonyms}
})
}
</script> </script>
</article> </article>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save