User manual and reference guide
- version 3.23.0
+ version 3.23.1
CodeMirror is a code-editor component that can be embedded in
diff --git a/lib/codemirror.js b/lib/codemirror.js
index 6f08c9871e..f5ac3f704b 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -6089,7 +6089,7 @@ window.CodeMirror = (function() {
// THE END
- CodeMirror.version = "3.23.0";
+ CodeMirror.version = "3.23.1";
return CodeMirror;
})();
diff --git a/package.json b/package.json
index 734ddbfae5..6ef41787be 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "codemirror",
- "version":"3.23.0",
+ "version":"3.23.1",
"main": "lib/codemirror.js",
"description": "In-browser code editing made bearable",
"licenses": [{"type": "MIT",
From 2af72ea8a6e489a21e6b0e3f7168f058bffb64ee Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Thu, 20 Mar 2014 11:39:15 +0100
Subject: [PATCH 031/127] Bump version number post-4.0
---
doc/manual.html | 2 +-
lib/codemirror.js | 2 +-
package.json | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/doc/manual.html b/doc/manual.html
index 09a7362c35..2fe8b703aa 100644
--- a/doc/manual.html
+++ b/doc/manual.html
@@ -63,7 +63,7 @@
User manual and reference guide
- version 4.0.3
+ version 4.0.4
CodeMirror is a code-editor component that can be embedded in
diff --git a/lib/codemirror.js b/lib/codemirror.js
index c3205cc189..744cca2596 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -7333,7 +7333,7 @@
// THE END
- CodeMirror.version = "4.0.3";
+ CodeMirror.version = "4.0.4";
return CodeMirror;
});
diff --git a/package.json b/package.json
index 496581b179..39946f35f8 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "codemirror",
- "version":"4.0.3",
+ "version":"4.0.4",
"main": "lib/codemirror.js",
"description": "In-browser code editing made bearable",
"licenses": [{"type": "MIT",
From 7c0d2080cf519f4afa3b53fb92667cf0015b5ff4 Mon Sep 17 00:00:00 2001
From: Bert Chang
Date: Mon, 17 Mar 2014 20:00:42 +0800
Subject: [PATCH 032/127] [vim] Use matchbracket.js for text objects
---
addon/edit/matchbrackets.js | 11 ++++++---
demo/vim.html | 3 +++
keymap/vim.js | 59 ++++++++++++++++++++++++++++++++-------------
test/vim_test.js | 7 ++++++
4 files changed, 59 insertions(+), 21 deletions(-)
diff --git a/addon/edit/matchbrackets.js b/addon/edit/matchbrackets.js
index 576ec143aa..96415b8d8d 100644
--- a/addon/edit/matchbrackets.js
+++ b/addon/edit/matchbrackets.js
@@ -26,11 +26,14 @@
match: found && found.ch == match.charAt(0), forward: dir > 0};
}
- function scanForBracket(cm, where, dir, style, config) {
+ // specifiedRegExp is used to specify which type of bracket to scan
+ // should be a regexp, e.g. /[[\]]/
+ function scanForBracket(cm, where, dir, style, config, specifiedRegExp) {
var maxScanLen = (config && config.maxScanLineLength) || 10000;
var maxScanLines = (config && config.maxScanLines) || 500;
- var stack = [], re = /[(){}[\]]/;
+ var stack = [];
+ var re = typeof specifiedRegExp == "undefined" ? /[(){}[\]]/ : specifiedRegExp;
var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1)
: Math.max(cm.firstLine() - 1, where.line - maxScanLines);
for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) {
@@ -102,7 +105,7 @@
CodeMirror.defineExtension("findMatchingBracket", function(pos, strict){
return findMatchingBracket(this, pos, strict);
});
- CodeMirror.defineExtension("scanForBracket", function(pos, dir, style){
- return scanForBracket(this, pos, dir, style);
+ CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, specifiedRegExp){
+ return scanForBracket(this, pos, dir, style, null, specifiedRegExp);
});
});
diff --git a/demo/vim.html b/demo/vim.html
index 0918bce45b..ad34660892 100644
--- a/demo/vim.html
+++ b/demo/vim.html
@@ -10,6 +10,7 @@
+
+
+
+
+
+
+
+
+
+Django template mode
+
+
+
+
+ Mode for HTML with embedded Django template markup.
+
+ MIME types defined: text/x-django
+
diff --git a/mode/index.html b/mode/index.html
index ecf77de17f..8b043b9cfc 100644
--- a/mode/index.html
+++ b/mode/index.html
@@ -40,6 +40,7 @@
CSS
Cython
D
+ Django (templating language)
diff
DTD
Dylan
From 0149b520842f00902d0a0d824d5c4b8518d927d6 Mon Sep 17 00:00:00 2001
From: as3boyan
Date: Tue, 25 Mar 2014 18:00:33 +0200
Subject: [PATCH 048/127] [haxe mode] Fix indentation for types
---
mode/haxe/haxe.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/mode/haxe/haxe.js b/mode/haxe/haxe.js
index 8582796404..d7ed7e6568 100644
--- a/mode/haxe/haxe.js
+++ b/mode/haxe/haxe.js
@@ -322,6 +322,7 @@ CodeMirror.defineMode("haxe", function(config, parserConfig) {
function typedef (type, value)
{
if(type == "variable" && /[A-Z]/.test(value.charAt(0))) { registerimport(value); return cont(); }
+ else if (type == "type" && /[A-Z]/.test(value.charAt(0))) { return cont(); }
}
function maybelabel(type) {
From 35eb77422ec53d4b33005a6a506b4a00c92aff74 Mon Sep 17 00:00:00 2001
From: Gabriel Horner
Date: Fri, 14 Mar 2014 12:19:49 -0400
Subject: [PATCH 049/127] [vim] Implement indented paste
- Adjusting indent of pasted block to current line
- Handle multi-line case, subsequent lines have their indent adjusted by their offset
to the first line.
- Add two tests for ]p to demonstrate this.
- Add [p to indent paste above
---
keymap/vim.js | 17 +++++++++++++++++
test/vim_test.js | 15 +++++++++++++++
2 files changed, 32 insertions(+)
diff --git a/keymap/vim.js b/keymap/vim.js
index f4a4491fdb..34a30e0f52 100644
--- a/keymap/vim.js
+++ b/keymap/vim.js
@@ -208,6 +208,11 @@
{ keys: ['[', '`'], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false } },
{ keys: [']', '\''], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true, linewise: true } },
{ keys: ['[', '\''], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false, linewise: true } },
+ // the next two aren't motions but must come before more general motion declarations
+ { keys: [']', 'p'], type: 'action', action: 'paste', isEdit: true,
+ actionArgs: { after: true, isEdit: true, matchIndent: true}},
+ { keys: ['[', 'p'], type: 'action', action: 'paste', isEdit: true,
+ actionArgs: { after: false, isEdit: true, matchIndent: true}},
{ keys: [']', 'character'], type: 'motion',
motion: 'moveToSymbol',
motionArgs: { forward: true, toJumplist: true}},
@@ -2032,6 +2037,18 @@
if (!text) {
return;
}
+ if (actionArgs.matchIndent) {
+ var indent = findFirstNonWhiteSpaceCharacter(cm.getLine(cm.getCursor().line));
+ // chomp last newline b/c don't want it to match /^\s*/gm
+ var chompedText = text.replace(/\n$/, '');
+ var wasChomped = text !== chompedText;
+ var firstIndent = text.match(/^\s*/)[0].length;
+ var text = chompedText.replace(/^\s*/gm, function(wspace) {
+ var newIndent = indent + (wspace.length - firstIndent);
+ return (newIndent < 0) ? "" : Array(newIndent + 1).join(' ');
+ });
+ text += wasChomped ? "\n" : "";
+ }
if (actionArgs.repeat > 1) {
var text = Array(actionArgs.repeat + 1).join(text);
}
diff --git a/test/vim_test.js b/test/vim_test.js
index 104707d269..0117193084 100644
--- a/test/vim_test.js
+++ b/test/vim_test.js
@@ -1243,6 +1243,21 @@ testVim('p_lastline', function(cm, vim, helpers) {
eq('___\n a\nd\n a\nd', cm.getValue());
helpers.assertCursorAt(1, 2);
}, { value: '___' });
+testVim(']p_first_indent_is_smaller', function(cm, vim, helpers) {
+ helpers.getRegisterController().pushText('"', 'yank', ' abc\n def\n', true);
+ helpers.doKeys(']', 'p');
+ eq(' ___\n abc\n def', cm.getValue());
+}, { value: ' ___' });
+testVim(']p_first_indent_is_larger', function(cm, vim, helpers) {
+ helpers.getRegisterController().pushText('"', 'yank', ' abc\n def\n', true);
+ helpers.doKeys(']', 'p');
+ eq(' ___\n abc\ndef', cm.getValue());
+}, { value: ' ___' });
+testVim('[p', function(cm, vim, helpers) {
+ helpers.getRegisterController().pushText('"', 'yank', ' abc\n def\n', true);
+ helpers.doKeys('[', 'p');
+ eq(' abc\n def\n ___', cm.getValue());
+}, { value: ' ___' });
testVim('P', function(cm, vim, helpers) {
cm.setCursor(0, 1);
helpers.getRegisterController().pushText('"', 'yank', 'abc\ndef', false);
From ebffc6b4db1c0a7e04030db021f1df8b4619aebe Mon Sep 17 00:00:00 2001
From: Gabriel Horner
Date: Fri, 21 Mar 2014 17:36:04 -0400
Subject: [PATCH 050/127] [vim] Indented paste respects indentWithTabs and
tabSize
---
keymap/vim.js | 24 ++++++++++++++++++++----
test/vim_test.js | 10 ++++++++++
2 files changed, 30 insertions(+), 4 deletions(-)
diff --git a/keymap/vim.js b/keymap/vim.js
index 34a30e0f52..45bc6ad945 100644
--- a/keymap/vim.js
+++ b/keymap/vim.js
@@ -2038,14 +2038,30 @@
return;
}
if (actionArgs.matchIndent) {
- var indent = findFirstNonWhiteSpaceCharacter(cm.getLine(cm.getCursor().line));
+ // length that considers tabs and cm.options.tabSize
+ var whitespaceLength = function(str) {
+ var tabs = (str.split("\t").length - 1);
+ var spaces = (str.split(" ").length - 1);
+ return tabs * cm.options.tabSize + spaces * 1;
+ };
+ var currentLine = cm.getLine(cm.getCursor().line);
+ var indent = whitespaceLength(currentLine.match(/^\s*/)[0]);
// chomp last newline b/c don't want it to match /^\s*/gm
var chompedText = text.replace(/\n$/, '');
var wasChomped = text !== chompedText;
- var firstIndent = text.match(/^\s*/)[0].length;
+ var firstIndent = whitespaceLength(text.match(/^\s*/)[0]);
var text = chompedText.replace(/^\s*/gm, function(wspace) {
- var newIndent = indent + (wspace.length - firstIndent);
- return (newIndent < 0) ? "" : Array(newIndent + 1).join(' ');
+ var newIndent = indent + (whitespaceLength(wspace) - firstIndent);
+ if (newIndent < 0) {
+ return "";
+ }
+ else if (cm.options.indentWithTabs) {
+ var quotient = Math.floor(newIndent / cm.options.tabSize);
+ return Array(quotient + 1).join('\t');
+ }
+ else {
+ return Array(newIndent + 1).join(' ');
+ }
});
text += wasChomped ? "\n" : "";
}
diff --git a/test/vim_test.js b/test/vim_test.js
index 0117193084..2dbbb13ec3 100644
--- a/test/vim_test.js
+++ b/test/vim_test.js
@@ -1253,6 +1253,16 @@ testVim(']p_first_indent_is_larger', function(cm, vim, helpers) {
helpers.doKeys(']', 'p');
eq(' ___\n abc\ndef', cm.getValue());
}, { value: ' ___' });
+testVim(']p_with_tab_indents', function(cm, vim, helpers) {
+ helpers.getRegisterController().pushText('"', 'yank', '\t\tabc\n\t\t\tdef\n', true);
+ helpers.doKeys(']', 'p');
+ eq('\t___\n\tabc\n\t\tdef', cm.getValue());
+}, { value: '\t___', indentWithTabs: true});
+testVim(']p_with_spaces_translated_to_tabs', function(cm, vim, helpers) {
+ helpers.getRegisterController().pushText('"', 'yank', ' abc\n def\n', true);
+ helpers.doKeys(']', 'p');
+ eq('\t___\n\tabc\n\t\tdef', cm.getValue());
+}, { value: '\t___', indentWithTabs: true, tabSize: 2 });
testVim('[p', function(cm, vim, helpers) {
helpers.getRegisterController().pushText('"', 'yank', ' abc\n def\n', true);
helpers.doKeys('[', 'p');
From f005c725ff23c0a6364741f0ec3794be0eba2c52 Mon Sep 17 00:00:00 2001
From: Shubham Jain
Date: Fri, 21 Mar 2014 05:24:00 +0530
Subject: [PATCH 051/127] [vim] Reset lastHPos tracking on click
---
keymap/vim.js | 16 +++++++++++++---
lib/codemirror.js | 4 +++-
2 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/keymap/vim.js b/keymap/vim.js
index 45bc6ad945..4d9f554c73 100644
--- a/keymap/vim.js
+++ b/keymap/vim.js
@@ -352,12 +352,14 @@
cm.setOption('disableInput', true);
CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"});
cm.on('beforeSelectionChange', beforeSelectionChange);
+ cm.on('cursorActivity', onCursorActivity);
maybeInitVimState(cm);
CodeMirror.on(cm.getInputField(), 'paste', getOnPasteFn(cm));
} else if (cm.state.vim) {
cm.setOption('keyMap', 'default');
cm.setOption('disableInput', false);
cm.off('beforeSelectionChange', beforeSelectionChange);
+ cm.off('cursorActivity', onCursorActivity);
CodeMirror.off(cm.getInputField(), 'paste', getOnPasteFn(cm));
cm.state.vim = null;
}
@@ -374,6 +376,14 @@
head: pos}]);
}
}
+ function onCursorActivity(cm, origin) {
+ if (origin == '*mouse') {
+ var cur = cm.doc.getCursor();
+ var vim = cm.state.vim;
+ if (vim.insertMode || vim.exMode) return;
+ vim.lastHPos = cur.ch;
+ }
+ }
function getOnPasteFn(cm) {
var vim = cm.state.vim;
if (!vim.onPasteFn) {
@@ -1906,7 +1916,7 @@
if (!vimGlobalState.macroModeState.isPlaying) {
// Only record if not replaying.
cm.on('change', onChange);
- cm.on('cursorActivity', onCursorActivity);
+ cm.on('cursorActivity', onCursorActivityInInsertMode);
CodeMirror.on(cm.getInputField(), 'keydown', onKeyEventTargetKeyDown);
}
},
@@ -3918,7 +3928,7 @@
var isPlaying = macroModeState.isPlaying;
if (!isPlaying) {
cm.off('change', onChange);
- cm.off('cursorActivity', onCursorActivity);
+ cm.off('cursorActivity', onCursorActivityInInsertMode);
CodeMirror.off(cm.getInputField(), 'keydown', onKeyEventTargetKeyDown);
}
if (!isPlaying && vim.insertModeRepeat > 1) {
@@ -4041,7 +4051,7 @@
* - For tracking cursor activity in insert mode.
* - Should only be active in insert mode.
*/
- function onCursorActivity() {
+ function onCursorActivityInInsertMode() {
var macroModeState = vimGlobalState.macroModeState;
if (macroModeState.isPlaying) { return; }
var lastChange = macroModeState.lastInsertModeChanges;
diff --git a/lib/codemirror.js b/lib/codemirror.js
index 81afc4c0ae..c7bc95ab69 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -1117,6 +1117,7 @@
// Set a new selection.
function setSelection(doc, sel, options) {
+ if(options && options.origin && doc.cm) doc.cm.curOp.origin = options.origin;
setSelectionNoUndo(doc, sel, options);
addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);
}
@@ -1869,6 +1870,7 @@
updateInput: null, // Whether to reset the input textarea
typing: false, // Whether this reset should be careful to leave existing text (for compositing)
changeObjs: null, // Accumulated changes, for firing change events
+ origin: null, // Selection's origin
cursorActivity: false, // Whether to fire a cursorActivity event
selectionChanged: false, // Whether the selection needs to be redrawn
updateMaxLine: false, // Set when the widest line needs to be determined anew
@@ -1939,7 +1941,7 @@
signal(cm, "change", cm, op.changeObjs[i]);
signal(cm, "changes", cm, op.changeObjs);
}
- if (op.cursorActivity) signal(cm, "cursorActivity", cm);
+ if (op.cursorActivity) signal(cm, "cursorActivity", cm, op.origin);
if (delayed) for (var i = 0; i < delayed.length; ++i) delayed[i]();
}
From 9e6cbfa331a2c73b64391702b1e450dc45483e50 Mon Sep 17 00:00:00 2001
From: Yunchi Luo
Date: Tue, 25 Mar 2014 18:55:37 +0100
Subject: [PATCH 052/127] [vim] Merge cursorActivity handlers + cleanup
---
keymap/vim.js | 39 +++++++++++++++++----------------------
lib/codemirror.js | 2 +-
2 files changed, 18 insertions(+), 23 deletions(-)
diff --git a/keymap/vim.js b/keymap/vim.js
index 4d9f554c73..9996687cc3 100644
--- a/keymap/vim.js
+++ b/keymap/vim.js
@@ -376,14 +376,6 @@
head: pos}]);
}
}
- function onCursorActivity(cm, origin) {
- if (origin == '*mouse') {
- var cur = cm.doc.getCursor();
- var vim = cm.state.vim;
- if (vim.insertMode || vim.exMode) return;
- vim.lastHPos = cur.ch;
- }
- }
function getOnPasteFn(cm) {
var vim = cm.state.vim;
if (!vim.onPasteFn) {
@@ -1916,7 +1908,6 @@
if (!vimGlobalState.macroModeState.isPlaying) {
// Only record if not replaying.
cm.on('change', onChange);
- cm.on('cursorActivity', onCursorActivityInInsertMode);
CodeMirror.on(cm.getInputField(), 'keydown', onKeyEventTargetKeyDown);
}
},
@@ -3928,7 +3919,6 @@
var isPlaying = macroModeState.isPlaying;
if (!isPlaying) {
cm.off('change', onChange);
- cm.off('cursorActivity', onCursorActivityInInsertMode);
CodeMirror.off(cm.getInputField(), 'keydown', onKeyEventTargetKeyDown);
}
if (!isPlaying && vim.insertModeRepeat > 1) {
@@ -3938,8 +3928,8 @@
vim.lastEditInputState.repeatOverride = vim.insertModeRepeat;
}
delete vim.insertModeRepeat;
- cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1);
vim.insertMode = false;
+ cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1);
cm.setOption('keyMap', 'vim');
cm.setOption('disableInput', true);
cm.toggleOverwrite(false); // exit replace mode if we were in it.
@@ -4048,18 +4038,23 @@
/**
* Listens for any kind of cursor activity on CodeMirror.
- * - For tracking cursor activity in insert mode.
- * - Should only be active in insert mode.
*/
- function onCursorActivityInInsertMode() {
- var macroModeState = vimGlobalState.macroModeState;
- if (macroModeState.isPlaying) { return; }
- var lastChange = macroModeState.lastInsertModeChanges;
- if (lastChange.expectCursorActivityForChange) {
- lastChange.expectCursorActivityForChange = false;
- } else {
- // Cursor moved outside the context of an edit. Reset the change.
- lastChange.changes = [];
+ function onCursorActivity(cm, origin) {
+ var vim = cm.state.vim;
+ if (vim.insertMode) {
+ // Tracking cursor activity in insert mode (for macro support).
+ var macroModeState = vimGlobalState.macroModeState;
+ if (macroModeState.isPlaying) { return; }
+ var lastChange = macroModeState.lastInsertModeChanges;
+ if (lastChange.expectCursorActivityForChange) {
+ lastChange.expectCursorActivityForChange = false;
+ } else {
+ // Cursor moved outside the context of an edit. Reset the change.
+ lastChange.changes = [];
+ }
+ } else if (origin == '*mouse') {
+ // Reset lastHPos if mouse click was done in normal mode.
+ vim.lastHPos = cm.doc.getCursor().ch;
}
}
diff --git a/lib/codemirror.js b/lib/codemirror.js
index c7bc95ab69..c8ff38fca2 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -1117,7 +1117,7 @@
// Set a new selection.
function setSelection(doc, sel, options) {
- if(options && options.origin && doc.cm) doc.cm.curOp.origin = options.origin;
+ if (options && options.origin && doc.cm) doc.cm.curOp.origin = options.origin;
setSelectionNoUndo(doc, sel, options);
addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);
}
From dcfa81998e96f7d1803d1974ae6f94caab0f3dce Mon Sep 17 00:00:00 2001
From: Faiza Alsaied
Date: Sun, 23 Mar 2014 14:13:08 +0100
Subject: [PATCH 053/127] [vim] Implement aB, iB, ab and ib text objects.
---
keymap/vim.js | 7 +++++++
test/vim_test.js | 18 ++++++++++++++++++
2 files changed, 25 insertions(+)
diff --git a/keymap/vim.js b/keymap/vim.js
index 9996687cc3..7e9064af9c 100644
--- a/keymap/vim.js
+++ b/keymap/vim.js
@@ -1667,6 +1667,13 @@
var selfPaired = {'\'': true, '"': true};
var character = motionArgs.selectedCharacter;
+ // 'b' refers to '()' block.
+ // 'B' refers to '{}' block.
+ if (character == 'b') {
+ character = '(';
+ } else if (character == 'B') {
+ character = '{';
+ }
// Inclusive is the difference between a and i
// TODO: Instead of using the additional text object map to perform text
diff --git a/test/vim_test.js b/test/vim_test.js
index 2dbbb13ec3..44a8b8b902 100644
--- a/test/vim_test.js
+++ b/test/vim_test.js
@@ -1015,18 +1015,32 @@ testEdit('daW_end_punct', 'foo \tbAr.', /A/, 'daW', 'foo');
// Open and close on same line
testEdit('di(_open_spc', 'foo (bAr) baz', /\(/, 'di(', 'foo () baz');
testEdit('di)_open_spc', 'foo (bAr) baz', /\(/, 'di)', 'foo () baz');
+testEdit('dib_open_spc', 'foo (bAr) baz', /\(/, 'dib', 'foo () baz');
testEdit('da(_open_spc', 'foo (bAr) baz', /\(/, 'da(', 'foo baz');
testEdit('da)_open_spc', 'foo (bAr) baz', /\(/, 'da)', 'foo baz');
+testEdit('dab_open_spc', 'foo (bAr) baz', /\(/, 'dab', 'foo baz');
testEdit('di(_middle_spc', 'foo (bAr) baz', /A/, 'di(', 'foo () baz');
testEdit('di)_middle_spc', 'foo (bAr) baz', /A/, 'di)', 'foo () baz');
+testEdit('dib_middle_spc', 'foo (bAr) baz', /A/, 'dib', 'foo () baz');
testEdit('da(_middle_spc', 'foo (bAr) baz', /A/, 'da(', 'foo baz');
testEdit('da)_middle_spc', 'foo (bAr) baz', /A/, 'da)', 'foo baz');
+testEdit('dab_middle_spc', 'foo (bAr) baz', /A/, 'dab', 'foo baz');
testEdit('di(_close_spc', 'foo (bAr) baz', /\)/, 'di(', 'foo () baz');
testEdit('di)_close_spc', 'foo (bAr) baz', /\)/, 'di)', 'foo () baz');
+testEdit('dib_close_spc', 'foo (bAr) baz', /\)/, 'dib', 'foo () baz');
testEdit('da(_close_spc', 'foo (bAr) baz', /\)/, 'da(', 'foo baz');
testEdit('da)_close_spc', 'foo (bAr) baz', /\)/, 'da)', 'foo baz');
+testEdit('dab_close_spc', 'foo (bAr) baz', /\)/, 'dab', 'foo baz');
+
+// delete around and inner b.
+testEdit('dab_on_(_should_delete_around_()block', 'o( in(abc) )', /\(a/, 'dab', 'o( in )');
+testEdit('dib_on_(_should_delete_inner_()block', 'o( in(abc) )', /\(a/, 'dib', 'o( in() )');
+
+// delete around and inner B.
+testEdit('daB_on_{_should_delete_around_{}block', 'o{ in{abc} }', /{a/, 'daB', 'o{ in }');
+testEdit('diB_on_{_should_delete_inner_{}block', 'o{ in{abc} }', /{a/, 'diB', 'o{ in{} }');
testEdit('da{_on_{_should_delete_inner_block', 'o{ in{abc} }', /{a/, 'da{', 'o{ in }');
testEdit('di[_on_(_should_not_delete', 'foo (bAr) baz', /\(/, 'di[', 'foo (bAr) baz');
@@ -1038,14 +1052,18 @@ testMotion('di(_outside_should_stay', ['d', 'i', '('], { line: 0, ch: 0}, { line
// Open and close on different lines, equally indented
testEdit('di{_middle_spc', 'a{\n\tbar\n}b', /r/, 'di{', 'a{}b');
testEdit('di}_middle_spc', 'a{\n\tbar\n}b', /r/, 'di}', 'a{}b');
+testEdit('diB_middle_spc', 'a{\n\tbar\n}b', /r/, 'diB', 'a{}b');
testEdit('da{_middle_spc', 'a{\n\tbar\n}b', /r/, 'da{', 'ab');
testEdit('da}_middle_spc', 'a{\n\tbar\n}b', /r/, 'da}', 'ab');
+testEdit('daB_middle_spc', 'a{\n\tbar\n}b', /r/, 'daB', 'ab');
// open and close on diff lines, open indented less than close
testEdit('di{_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'di{', 'a{}b');
testEdit('di}_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'di}', 'a{}b');
+testEdit('diB_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'diB', 'a{}b');
testEdit('da{_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'da{', 'ab');
testEdit('da}_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'da}', 'ab');
+testEdit('daB_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'daB', 'ab');
// open and close on diff lines, open indented more than close
testEdit('di[_middle_spc', 'a\t[\n\tbar\n]b', /r/, 'di[', 'a\t[]b');
From 3b6fa1c1fbd46b4bc37aab01d3f524cbb168e5c8 Mon Sep 17 00:00:00 2001
From: Yunchi Luo
Date: Tue, 25 Mar 2014 19:14:33 +0100
Subject: [PATCH 054/127] [vim] Delete unnecessary aB/iB/ab/ib tests
---
test/vim_test.js | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/test/vim_test.js b/test/vim_test.js
index 44a8b8b902..0d1cc066d4 100644
--- a/test/vim_test.js
+++ b/test/vim_test.js
@@ -1018,25 +1018,19 @@ testEdit('di)_open_spc', 'foo (bAr) baz', /\(/, 'di)', 'foo () baz');
testEdit('dib_open_spc', 'foo (bAr) baz', /\(/, 'dib', 'foo () baz');
testEdit('da(_open_spc', 'foo (bAr) baz', /\(/, 'da(', 'foo baz');
testEdit('da)_open_spc', 'foo (bAr) baz', /\(/, 'da)', 'foo baz');
-testEdit('dab_open_spc', 'foo (bAr) baz', /\(/, 'dab', 'foo baz');
testEdit('di(_middle_spc', 'foo (bAr) baz', /A/, 'di(', 'foo () baz');
testEdit('di)_middle_spc', 'foo (bAr) baz', /A/, 'di)', 'foo () baz');
-testEdit('dib_middle_spc', 'foo (bAr) baz', /A/, 'dib', 'foo () baz');
testEdit('da(_middle_spc', 'foo (bAr) baz', /A/, 'da(', 'foo baz');
testEdit('da)_middle_spc', 'foo (bAr) baz', /A/, 'da)', 'foo baz');
-testEdit('dab_middle_spc', 'foo (bAr) baz', /A/, 'dab', 'foo baz');
testEdit('di(_close_spc', 'foo (bAr) baz', /\)/, 'di(', 'foo () baz');
testEdit('di)_close_spc', 'foo (bAr) baz', /\)/, 'di)', 'foo () baz');
-testEdit('dib_close_spc', 'foo (bAr) baz', /\)/, 'dib', 'foo () baz');
testEdit('da(_close_spc', 'foo (bAr) baz', /\)/, 'da(', 'foo baz');
testEdit('da)_close_spc', 'foo (bAr) baz', /\)/, 'da)', 'foo baz');
-testEdit('dab_close_spc', 'foo (bAr) baz', /\)/, 'dab', 'foo baz');
// delete around and inner b.
testEdit('dab_on_(_should_delete_around_()block', 'o( in(abc) )', /\(a/, 'dab', 'o( in )');
-testEdit('dib_on_(_should_delete_inner_()block', 'o( in(abc) )', /\(a/, 'dib', 'o( in() )');
// delete around and inner B.
testEdit('daB_on_{_should_delete_around_{}block', 'o{ in{abc} }', /{a/, 'daB', 'o{ in }');
@@ -1052,7 +1046,6 @@ testMotion('di(_outside_should_stay', ['d', 'i', '('], { line: 0, ch: 0}, { line
// Open and close on different lines, equally indented
testEdit('di{_middle_spc', 'a{\n\tbar\n}b', /r/, 'di{', 'a{}b');
testEdit('di}_middle_spc', 'a{\n\tbar\n}b', /r/, 'di}', 'a{}b');
-testEdit('diB_middle_spc', 'a{\n\tbar\n}b', /r/, 'diB', 'a{}b');
testEdit('da{_middle_spc', 'a{\n\tbar\n}b', /r/, 'da{', 'ab');
testEdit('da}_middle_spc', 'a{\n\tbar\n}b', /r/, 'da}', 'ab');
testEdit('daB_middle_spc', 'a{\n\tbar\n}b', /r/, 'daB', 'ab');
@@ -1060,10 +1053,8 @@ testEdit('daB_middle_spc', 'a{\n\tbar\n}b', /r/, 'daB', 'ab');
// open and close on diff lines, open indented less than close
testEdit('di{_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'di{', 'a{}b');
testEdit('di}_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'di}', 'a{}b');
-testEdit('diB_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'diB', 'a{}b');
testEdit('da{_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'da{', 'ab');
testEdit('da}_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'da}', 'ab');
-testEdit('daB_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'daB', 'ab');
// open and close on diff lines, open indented more than close
testEdit('di[_middle_spc', 'a\t[\n\tbar\n]b', /r/, 'di[', 'a\t[]b');
From 5b366e64fbe970128ab530a77c192358e18d9db7 Mon Sep 17 00:00:00 2001
From: Faiza Alsaied
Date: Sat, 22 Mar 2014 23:55:22 +0100
Subject: [PATCH 055/127] [vim] Fixed append to register feature.
---
keymap/vim.js | 15 ++++++++-------
test/vim_test.js | 46 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 54 insertions(+), 7 deletions(-)
diff --git a/keymap/vim.js b/keymap/vim.js
index 7e9064af9c..9ad027a0d6 100644
--- a/keymap/vim.js
+++ b/keymap/vim.js
@@ -786,8 +786,10 @@
},
pushText: function(text, linewise) {
// if this register has ever been set to linewise, use linewise.
- if (linewise || this.linewise) {
- this.keyBuffer.push('\n');
+ if (linewise) {
+ if (!this.linewise) {
+ this.keyBuffer.push('\n');
+ }
this.linewise = true;
}
this.keyBuffer.push(text);
@@ -864,14 +866,13 @@
// If we've gotten to this point, we've actually specified a register
var append = isUpperCase(registerName);
if (append) {
- register.append(text, linewise);
- // The unnamed register always has the same value as the last used
- // register.
- this.unnamedRegister.append(text, linewise);
+ register.pushText(text, linewise);
} else {
register.setText(text, linewise);
- this.unnamedRegister.setText(text, linewise);
}
+ // The unnamed register always has the same value as the last used
+ // register.
+ this.unnamedRegister.setText(register.toString(), linewise);
},
// Gets the register named @name. If one of @name doesn't already exist,
// create it. If @name is invalid, return the unnamedRegister.
diff --git a/test/vim_test.js b/test/vim_test.js
index 0d1cc066d4..5d50d84ef0 100644
--- a/test/vim_test.js
+++ b/test/vim_test.js
@@ -1926,6 +1926,50 @@ testVim('yank_register', function(cm, vim, helpers) {
});
helpers.doKeys(':');
}, { value: 'foo\nbar'});
+testVim('yank_append_line_to_line_register', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('"', 'a', 'y', 'y');
+ helpers.doKeys('j', '"', 'A', 'y', 'y');
+ cm.openDialog = helpers.fakeOpenDialog('registers');
+ cm.openNotification = helpers.fakeOpenNotification(function(text) {
+ is(/a\s+foo\nbar/.test(text));
+ is(/"\s+foo\nbar/.test(text));
+ });
+ helpers.doKeys(':');
+}, { value: 'foo\nbar'});
+testVim('yank_append_word_to_word_register', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('"', 'a', 'y', 'w');
+ helpers.doKeys('j', '"', 'A', 'y', 'w');
+ cm.openDialog = helpers.fakeOpenDialog('registers');
+ cm.openNotification = helpers.fakeOpenNotification(function(text) {
+ is(/a\s+foobar/.test(text));
+ is(/"\s+foobar/.test(text));
+ });
+ helpers.doKeys(':');
+}, { value: 'foo\nbar'});
+testVim('yank_append_line_to_word_register', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('"', 'a', 'y', 'w');
+ helpers.doKeys('j', '"', 'A', 'y', 'y');
+ cm.openDialog = helpers.fakeOpenDialog('registers');
+ cm.openNotification = helpers.fakeOpenNotification(function(text) {
+ is(/a\s+foo\nbar/.test(text));
+ is(/"\s+foo\nbar/.test(text));
+ });
+ helpers.doKeys(':');
+}, { value: 'foo\nbar'});
+testVim('yank_append_word_to_line_register', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('"', 'a', 'y', 'y');
+ helpers.doKeys('j', '"', 'A', 'y', 'w');
+ cm.openDialog = helpers.fakeOpenDialog('registers');
+ cm.openNotification = helpers.fakeOpenNotification(function(text) {
+ is(/a\s+foo\nbar/.test(text));
+ is(/"\s+foo\nbar/.test(text));
+ });
+ helpers.doKeys(':');
+}, { value: 'foo\nbar'});
testVim('macro_register', function(cm, vim, helpers) {
cm.setCursor(0, 0);
helpers.doKeys('q', 'a', 'i');
@@ -2982,3 +3026,5 @@ testVim('beforeSelectionChange', function(cm, vim, helpers) {
cm.setCursor(0, 100);
eqPos(cm.getCursor('head'), cm.getCursor('anchor'));
}, { value: 'abc' });
+
+
From bfc600a27cc738870203dcb331ad0fb75595df7f Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Wed, 26 Mar 2014 08:37:32 +0100
Subject: [PATCH 056/127] [show-hint addon] Add an origin string to completion
changes
Issue #2406
---
addon/hint/show-hint.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js
index a90c8f2aa3..8d291d4b0a 100644
--- a/addon/hint/show-hint.js
+++ b/addon/hint/show-hint.js
@@ -53,7 +53,8 @@
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);
+ else this.cm.replaceRange(getText(completion), completion.from || data.from,
+ completion.to || data.to, "complete");
CodeMirror.signal(data, "pick", completion);
this.close();
},
From 5b2d8991884480c4f498afabd55daa2c57bb76e8 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Wed, 26 Mar 2014 18:11:47 +0100
Subject: [PATCH 057/127] Fix file dropping
Wrap FileReader.onload in operation.
---
lib/codemirror.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/codemirror.js b/lib/codemirror.js
index c8ff38fca2..6284cf8ff2 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -2746,7 +2746,7 @@
var n = files.length, text = Array(n), read = 0;
var loadFile = function(file, i) {
var reader = new FileReader;
- reader.onload = function() {
+ reader.onload = operation(cm, function() {
text[i] = reader.result;
if (++read == n) {
pos = clipPos(cm.doc, pos);
@@ -2754,7 +2754,7 @@
makeChange(cm.doc, change);
setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
}
- };
+ });
reader.readAsText(file);
};
for (var i = 0; i < n; ++i) loadFile(files[i], i);
From 47814e172aa47fe9f99f69db166f3b966ce052b7 Mon Sep 17 00:00:00 2001
From: Shubham Jain
Date: Sun, 23 Mar 2014 04:10:04 +0530
Subject: [PATCH 058/127] [vim] Partial fix for . in visual mode
---
keymap/vim.js | 18 +++++++++++++++++-
test/vim_test.js | 8 ++++++++
2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/keymap/vim.js b/keymap/vim.js
index 9ad027a0d6..8dec665d95 100644
--- a/keymap/vim.js
+++ b/keymap/vim.js
@@ -1326,17 +1326,33 @@
motionArgs.inclusive = true;
}
// Swap start and end if motion was backward.
- if (cursorIsBefore(curEnd, curStart)) {
+ if (curEnd && cursorIsBefore(curEnd, curStart)) {
var tmp = curStart;
curStart = curEnd;
curEnd = tmp;
inverted = true;
+ } else if (!curEnd) {
+ curEnd = copyCursor(curStart);
}
if (motionArgs.inclusive && !(vim.visualMode && inverted)) {
// Move the selection end one to the right to include the last
// character.
curEnd.ch++;
}
+ if (operatorArgs.relCurEnd) {
+ curEnd.line = curStart.line + operatorArgs.relCurEnd.line;
+ if (operatorArgs.relCurEnd.line) curEnd.ch = operatorArgs.relCurEnd.ch;
+ else curEnd.ch = curStart.ch + operatorArgs.relCurEnd.ch;
+ }
+ else if (vim.visualMode) {
+ // Set relative curEnd position w.r.t. curStart in operatorArgs
+ // to be used by repeatLastEdit action.
+ var relCurEnd = Pos();
+ relCurEnd.line = curEnd.line - curStart.line;
+ if (relCurEnd.line) relCurEnd.ch = curEnd.ch;
+ else relCurEnd.ch = curEnd.ch - curStart.ch;
+ operatorArgs.relCurEnd = relCurEnd;
+ }
var linewise = motionArgs.linewise ||
(vim.visualMode && vim.visualLine);
if (linewise) {
diff --git a/test/vim_test.js b/test/vim_test.js
index 5d50d84ef0..445e79bf85 100644
--- a/test/vim_test.js
+++ b/test/vim_test.js
@@ -2109,6 +2109,14 @@ testVim('._delete_repeat', function(cm, vim, helpers) {
eq('zzce', cm.getValue());
helpers.assertCursorAt(0, 1);
}, { value: 'zzabcde'});
+testVim('._visual_>', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('V', 'j', '>');
+ cm.setCursor(2, 0)
+ helpers.doKeys('.');
+ eq(' 1\n 2\n 3\n 4', cm.getValue());
+ helpers.assertCursorAt(2, 2);
+}, { value: '1\n2\n3\n4'});
testVim('f;', function(cm, vim, helpers) {
cm.setCursor(0, 0);
helpers.doKeys('f', 'x');
From 88b26fca6c2df158bd0fe4c8d32be6029ffc503f Mon Sep 17 00:00:00 2001
From: Yunchi Luo
Date: Wed, 26 Mar 2014 18:20:47 +0100
Subject: [PATCH 059/127] [vim] Clean up visual mode . fix a bit, fix linewise
---
keymap/vim.js | 26 ++++++++++++--------------
1 file changed, 12 insertions(+), 14 deletions(-)
diff --git a/keymap/vim.js b/keymap/vim.js
index 8dec665d95..d1a9a033d6 100644
--- a/keymap/vim.js
+++ b/keymap/vim.js
@@ -1339,19 +1339,17 @@
// character.
curEnd.ch++;
}
- if (operatorArgs.relCurEnd) {
- curEnd.line = curStart.line + operatorArgs.relCurEnd.line;
- if (operatorArgs.relCurEnd.line) curEnd.ch = operatorArgs.relCurEnd.ch;
- else curEnd.ch = curStart.ch + operatorArgs.relCurEnd.ch;
- }
- else if (vim.visualMode) {
- // Set relative curEnd position w.r.t. curStart in operatorArgs
- // to be used by repeatLastEdit action.
- var relCurEnd = Pos();
- relCurEnd.line = curEnd.line - curStart.line;
- if (relCurEnd.line) relCurEnd.ch = curEnd.ch;
- else relCurEnd.ch = curEnd.ch - curStart.ch;
- operatorArgs.relCurEnd = relCurEnd;
+ if (operatorArgs.selOffset) {
+ // Replaying a visual mode operation
+ curEnd.line = curStart.line + operatorArgs.selOffset.line;
+ if (operatorArgs.selOffset.line) {curEnd.ch = operatorArgs.selOffset.ch; }
+ else { curEnd.ch = curStart.ch + operatorArgs.selOffset.ch; }
+ } else if (vim.visualMode) {
+ var selOffset = Pos();
+ selOffset.line = curEnd.line - curStart.line;
+ if (selOffset.line) { selOffset.ch = curEnd.ch; }
+ else { selOffset.ch = curEnd.ch - curStart.ch; }
+ operatorArgs.selOffset = selOffset;
}
var linewise = motionArgs.linewise ||
(vim.visualMode && vim.visualLine);
@@ -1364,7 +1362,7 @@
}
operatorArgs.registerName = registerName;
// Keep track of linewise as it affects how paste and change behave.
- operatorArgs.linewise = linewise;
+ operatorArgs.linewise = linewise || operatorArgs.linewise;
operators[operator](cm, operatorArgs, vim, curStart,
curEnd, curOriginal);
if (vim.visualMode) {
From 6bda3bcbbd7c1fb59d817de0ee09635da39eff65 Mon Sep 17 00:00:00 2001
From: Yunchi Luo
Date: Sat, 29 Mar 2014 21:00:44 +0100
Subject: [PATCH 060/127] [vim] Fix linewise visual repeat
---
keymap/vim.js | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/keymap/vim.js b/keymap/vim.js
index d1a9a033d6..6fedf93292 100644
--- a/keymap/vim.js
+++ b/keymap/vim.js
@@ -1352,7 +1352,8 @@
operatorArgs.selOffset = selOffset;
}
var linewise = motionArgs.linewise ||
- (vim.visualMode && vim.visualLine);
+ (vim.visualMode && vim.visualLine) ||
+ operatorArgs.linewise;
if (linewise) {
// Expand selection to entire line.
expandSelectionToLine(cm, curStart, curEnd);
@@ -1362,7 +1363,7 @@
}
operatorArgs.registerName = registerName;
// Keep track of linewise as it affects how paste and change behave.
- operatorArgs.linewise = linewise || operatorArgs.linewise;
+ operatorArgs.linewise = linewise;
operators[operator](cm, operatorArgs, vim, curStart,
curEnd, curOriginal);
if (vim.visualMode) {
From 156ea7a6a2b2779e5e9c29ca56ae52b8c97a61bf Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Tue, 1 Apr 2014 11:40:33 +0200
Subject: [PATCH 061/127] Make refresh recompute the space the gutter takes up
When line numbers are off, and the editor was initialized in
a hidden position, the gutters would sit on top of the text.
Issue #2365
---
lib/codemirror.js | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/lib/codemirror.js b/lib/codemirror.js
index 6284cf8ff2..331b29aed2 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -328,9 +328,13 @@
}
}
gutters.style.display = i ? "" : "none";
- var width = gutters.offsetWidth;
+ updateGutterSpace(cm);
+ }
+
+ function updateGutterSpace(cm) {
+ var width = cm.display.gutters.offsetWidth;
cm.display.sizer.style.marginLeft = width + "px";
- if (i) cm.display.scrollbarH.style.left = cm.options.fixedGutter ? width + "px" : 0;
+ cm.display.scrollbarH.style.left = cm.options.fixedGutter ? width + "px" : 0;
}
// Compute the character length of a line, taking into account
@@ -502,9 +506,7 @@
display.lineNumWidth = display.lineNumInnerWidth + padding;
display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
display.lineGutter.style.width = display.lineNumWidth + "px";
- var width = display.gutters.offsetWidth;
- display.scrollbarH.style.left = cm.options.fixedGutter ? width + "px" : 0;
- display.sizer.style.marginLeft = width + "px";
+ updateGutterSpace(cm);
return true;
}
return false;
@@ -4197,6 +4199,7 @@
regChange(this);
clearCaches(this);
this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop);
+ updateGutterSpace(this);
if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
estimateLineHeights(this);
signal(this, "refresh", this);
From 3f1a7bb2f901f65fd5c1d4992153ec1975373c5a Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Tue, 1 Apr 2014 12:17:55 +0200
Subject: [PATCH 062/127] [overlay addon] Fix bug when overlay mode is itself
multiplexed
It assumed it saw all parts of the stream, and started
doing bad things when that was not the case.
Issue #2410
---
addon/mode/overlay.js | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/addon/mode/overlay.js b/addon/mode/overlay.js
index 6f556a13a7..c16b0c822d 100644
--- a/addon/mode/overlay.js
+++ b/addon/mode/overlay.js
@@ -23,7 +23,8 @@ CodeMirror.overlayMode = function(base, overlay, combine) {
base: CodeMirror.startState(base),
overlay: CodeMirror.startState(overlay),
basePos: 0, baseCur: null,
- overlayPos: 0, overlayCur: null
+ overlayPos: 0, overlayCur: null,
+ lineSeen: null
};
},
copyState: function(state) {
@@ -36,6 +37,12 @@ CodeMirror.overlayMode = function(base, overlay, combine) {
},
token: function(stream, state) {
+ if (stream.sol() || stream.string != state.lineSeen ||
+ Math.min(state.basePos, state.overlayPos) < stream.start) {
+ state.lineSeen = stream.string;
+ state.basePos = state.overlayPos = stream.start;
+ }
+
if (stream.start == state.basePos) {
state.baseCur = base.token(stream, state.base);
state.basePos = stream.pos;
@@ -46,7 +53,6 @@ CodeMirror.overlayMode = function(base, overlay, combine) {
state.overlayPos = stream.pos;
}
stream.pos = Math.min(state.basePos, state.overlayPos);
- if (stream.eol()) state.basePos = state.overlayPos = 0;
if (state.overlayCur == null) return state.baseCur;
if (state.baseCur != null && combine) return state.baseCur + " " + state.overlayCur;
From 32342a6a3d31ce700b8ada708f779c8f77b0e886 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Tue, 1 Apr 2014 17:17:02 +0200
Subject: [PATCH 063/127] Allow blankLine to return line-* and
line-background-* strings
(Experimental for now. Prompted by indentation guide discussion.)
---
lib/codemirror.js | 109 ++++++++++++++++++++++++++++++++++++------------------
test/test.js | 14 +++++++
2 files changed, 87 insertions(+), 36 deletions(-)
diff --git a/lib/codemirror.js b/lib/codemirror.js
index 331b29aed2..265879dbad 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -255,10 +255,10 @@
function wrappingChanged(cm) {
if (cm.options.lineWrapping) {
- cm.display.wrapper.className += " CodeMirror-wrap";
+ addClass(cm.display.wrapper, "CodeMirror-wrap");
cm.display.sizer.style.minWidth = "";
} else {
- cm.display.wrapper.className = cm.display.wrapper.className.replace(" CodeMirror-wrap", "");
+ rmClass(cm.display.wrapper, "CodeMirror-wrap");
findMaxLine(cm);
}
estimateLineHeights(cm);
@@ -1374,7 +1374,10 @@
doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) {
if (doc.frontier >= cm.display.viewFrom) { // Visible
var oldStyles = line.styles;
- line.styles = highlightLine(cm, line, state, true);
+ var highlighted = highlightLine(cm, line, state, true);
+ line.styles = highlighted.styles;
+ if (highlighted.classes) line.styleClasses = highlighted.classes;
+ else if (line.styleClasses) line.styleClasses = null;
var ischange = !oldStyles || oldStyles.length != line.styles.length;
for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i];
if (ischange) regLineChange(cm, doc.frontier, "text");
@@ -3027,11 +3030,11 @@
function showCrossHair(cm) {
var lineDiv = cm.display.lineDiv;
- lineDiv.className += " CodeMirror-crosshair";
+ addClass(lineDiv, "CodeMirror-crosshair");
function up(e) {
if (e.keyCode == 18 || !e.altKey) {
- lineDiv.className = lineDiv.className.replace(" CodeMirror-crosshair", "");
+ rmClass(lineDiv, "CodeMirror-crosshair");
off(document, "keyup", up);
off(document, "mouseover", up);
}
@@ -3064,8 +3067,7 @@
if (!cm.state.focused) {
signal(cm, "focus", cm);
cm.state.focused = true;
- if (cm.display.wrapper.className.search(/\bCodeMirror-focused\b/) == -1)
- cm.display.wrapper.className += " CodeMirror-focused";
+ addClass(cm.display.wrapper, "CodeMirror-focused");
if (!cm.curOp) {
resetInput(cm);
if (webkit) setTimeout(bind(resetInput, cm, true), 0); // Issue #1730
@@ -3078,7 +3080,7 @@
if (cm.state.focused) {
signal(cm, "blur", cm);
cm.state.focused = false;
- cm.display.wrapper.className = cm.display.wrapper.className.replace(" CodeMirror-focused", "");
+ rmClass(cm.display.wrapper, "CodeMirror-focused");
}
clearInterval(cm.display.blinker);
setTimeout(function() {if (!cm.state.focused) cm.display.shift = false;}, 150);
@@ -4137,9 +4139,9 @@
toggleOverwrite: function(value) {
if (value != null && value == this.state.overwrite) return;
if (this.state.overwrite = !this.state.overwrite)
- this.display.cursorDiv.className += " CodeMirror-overwrite";
+ addClass(this.display.cursorDiv, "CodeMirror-overwrite");
else
- this.display.cursorDiv.className = this.display.cursorDiv.className.replace(" CodeMirror-overwrite", "");
+ rmClass(this.display.cursorDiv, "CodeMirror-overwrite");
signal(this, "overwriteToggle", this, this.state.overwrite);
},
@@ -5509,13 +5511,34 @@
detachMarkedSpans(line);
}
+ function extractLineClasses(type, output) {
+ if (type) for (;;) {
+ var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/);
+ if (!lineClass) break;
+ type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);
+ var prop = lineClass[1] ? "bgClass" : "textClass";
+ if (output[prop] == null)
+ output[prop] = lineClass[2];
+ else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
+ output[prop] += " " + lineClass[2];
+ }
+ return type;
+ }
+
+ function callBlankLine(mode, state) {
+ if (mode.blankLine) return mode.blankLine(state);
+ if (!mode.innerMode) return;
+ var inner = CodeMirror.innerMode(mode, state);
+ if (inner.mode.blankLine) return inner.mode.blankLine(inner.state);
+ }
+
// Run the given mode's parser over a line, calling f for each token.
- function runMode(cm, text, mode, state, f, forceToEnd) {
+ function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) {
var flattenSpans = mode.flattenSpans;
if (flattenSpans == null) flattenSpans = cm.options.flattenSpans;
var curStart = 0, curStyle = null;
var stream = new StringStream(text, cm.options.tabSize), style;
- if (text == "" && mode.blankLine) mode.blankLine(state);
+ if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses);
while (!stream.eol()) {
if (stream.pos > cm.options.maxHighlightLength) {
flattenSpans = false;
@@ -5523,7 +5546,7 @@
stream.pos = text.length;
style = null;
} else {
- style = mode.token(stream, state);
+ style = extractLineClasses(mode.token(stream, state), lineClasses);
}
if (cm.options.addModeClass) {
var mName = CodeMirror.innerMode(mode, state).mode.name;
@@ -5550,11 +5573,11 @@
function highlightLine(cm, line, state, forceToEnd) {
// A styles array always starts with a number identifying the
// mode/overlays that it is based on (for easy invalidation).
- var st = [cm.state.modeGen];
+ var st = [cm.state.modeGen], lineClasses = {};
// Compute the base array of styles
runMode(cm, line.text, cm.doc.mode, state, function(end, style) {
st.push(end, style);
- }, forceToEnd);
+ }, lineClasses, forceToEnd);
// Run overlays, adjust style array.
for (var o = 0; o < cm.state.overlays.length; ++o) {
@@ -5579,15 +5602,19 @@
st[start+1] = cur ? cur + " " + style : style;
}
}
- });
+ }, lineClasses);
}
- return st;
+ return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null};
}
function getLineStyles(cm, line) {
- if (!line.styles || line.styles[0] != cm.state.modeGen)
- line.styles = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line)));
+ if (!line.styles || line.styles[0] != cm.state.modeGen) {
+ var result = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line)));
+ line.styles = result.styles;
+ if (result.classes) line.styleClasses = result.classes;
+ else if (line.styleClasses) line.styleClasses = null;
+ }
return line.styles;
}
@@ -5598,7 +5625,7 @@
var mode = cm.doc.mode;
var stream = new StringStream(text, cm.options.tabSize);
stream.start = stream.pos = startAt || 0;
- if (text == "" && mode.blankLine) mode.blankLine(state);
+ if (text == "") callBlankLine(mode, state);
while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) {
mode.token(stream, state);
stream.start = stream.pos;
@@ -5609,20 +5636,9 @@
// containing one or more styles) to a CSS style. This is cached,
// and also looks for line-wide styles.
var styleToClassCache = {}, styleToClassCacheWithMode = {};
- function interpretTokenStyle(style, builder) {
- if (!style) return null;
- for (;;) {
- var lineClass = style.match(/(?:^|\s+)line-(background-)?(\S+)/);
- if (!lineClass) break;
- style = style.slice(0, lineClass.index) + style.slice(lineClass.index + lineClass[0].length);
- var prop = lineClass[1] ? "bgClass" : "textClass";
- if (builder[prop] == null)
- builder[prop] = lineClass[2];
- else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(builder[prop]))
- builder[prop] += " " + lineClass[2];
- }
- if (/^\s*$/.test(style)) return null;
- var cache = builder.cm.options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
+ function interpretTokenStyle(style, options) {
+ if (!style || /^\s*$/.test(style)) return null;
+ var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
return cache[style] ||
(cache[style] = style.replace(/\S+/g, "cm-$&"));
}
@@ -5653,6 +5669,12 @@
builder.addToken = buildTokenBadBidi(builder.addToken, order);
builder.map = [];
insertLineContent(line, builder, getLineStyles(cm, line));
+ if (line.styleClasses) {
+ if (line.styleClasses.bgClass)
+ builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || "");
+ if (line.styleClasses.textClass)
+ builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || "");
+ }
// Ensure at least a single node is present, for measuring.
if (builder.map.length == 0)
@@ -5778,7 +5800,7 @@
var spans = line.markedSpans, allText = line.text, at = 0;
if (!spans) {
for (var i = 1; i < styles.length; i+=2)
- builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder));
+ builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options));
return;
}
@@ -5828,7 +5850,7 @@
spanStartStyle = "";
}
text = allText.slice(at, at = styles[i++]);
- style = interpretTokenStyle(styles[i++], builder);
+ style = interpretTokenStyle(styles[i++], builder.cm.options);
}
}
}
@@ -7035,6 +7057,21 @@
catch(e) { return document.body; }
};
+ function classTest(cls) { return new RegExp("\\b" + cls + "\\b\\s*"); }
+ function rmClass(node, cls) {
+ var test = classTest(cls);
+ if (test.test(node.className)) node.className = node.className.replace(test, "");
+ }
+ function addClass(node, cls) {
+ if (!classTest(cls).test(node.className)) node.className += " " + cls;
+ }
+ function joinClasses(a, b) {
+ var as = a.split(" ");
+ for (var i = 0; i < as.length; i++)
+ if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i];
+ return b;
+ }
+
// FEATURE DETECTION
// Detect drag-and-drop
diff --git a/test/test.js b/test/test.js
index b1b5594d2d..8c3a307d53 100644
--- a/test/test.js
+++ b/test/test.js
@@ -1776,6 +1776,20 @@ testCM("lineStyleFromMode", function(cm) {
is(/^\s*cm-span\s*$/.test(spanElts[0].className));
}, {value: "line1: [br] [br]\nline2: (par) (par)\nline3: "});
+testCM("lineStyleFromBlankLine", function(cm) {
+ CodeMirror.defineMode("lineStyleFromBlankLine_mode", function() {
+ return {token: function(stream) { stream.skipToEnd(); return "comment"; },
+ blankLine: function() { return "line-blank"; }};
+ });
+ cm.setOption("mode", "lineStyleFromBlankLine_mode");
+ var blankElts = byClassName(cm.getWrapperElement(), "blank");
+ eq(blankElts.length, 1);
+ eq(blankElts[0].nodeName, "PRE");
+ cm.replaceRange("x", Pos(1, 0));
+ blankElts = byClassName(cm.getWrapperElement(), "blank");
+ eq(blankElts.length, 0);
+}, {value: "foo\n\nbar"});
+
CodeMirror.registerHelper("xxx", "a", "A");
CodeMirror.registerHelper("xxx", "b", "B");
CodeMirror.defineMode("yyy", function() {
From 82bcf271aba6cb14776a3517f54d5d53428070d8 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Tue, 1 Apr 2014 17:29:31 +0200
Subject: [PATCH 064/127] [real-world uses] Add Filemanager
---
doc/realworld.html | 1 +
1 file changed, 1 insertion(+)
diff --git a/doc/realworld.html b/doc/realworld.html
index 08f0267856..ceb1b8ca2c 100644
--- a/doc/realworld.html
+++ b/doc/realworld.html
@@ -65,6 +65,7 @@
Farabi (modern Perl IDE)
FathomJS integration (slides with editors, again)
Fiddle Salad (web development environment)
+ Filemanager
Firefox Developer Tools
Firepad (collaborative text editor)
Gerrit 's diff view
From f77e7915edb2b4f2f9f9fbc295aaa3de7bdd332c Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Tue, 1 Apr 2014 17:31:39 +0200
Subject: [PATCH 065/127] Drop font-family rules from themes
Closes #2415
---
theme/ambiance.css | 1 -
theme/lesser-dark.css | 4 ----
theme/mdn-like.css | 2 +-
theme/pastel-on-dark.css | 1 -
theme/rubyblue.css | 2 --
theme/solarized.css | 1 -
6 files changed, 1 insertion(+), 10 deletions(-)
diff --git a/theme/ambiance.css b/theme/ambiance.css
index 3a54b2a022..48ba091fb3 100644
--- a/theme/ambiance.css
+++ b/theme/ambiance.css
@@ -41,7 +41,6 @@
.cm-s-ambiance.CodeMirror {
line-height: 1.40em;
- font-family: Monaco, Menlo,"Andale Mono","lucida console","Courier New",monospace !important;
color: #E6E1DC;
background-color: #202020;
-webkit-box-shadow: inset 0 0 10px black;
diff --git a/theme/lesser-dark.css b/theme/lesser-dark.css
index c32559663b..b8e77c2794 100644
--- a/theme/lesser-dark.css
+++ b/theme/lesser-dark.css
@@ -5,10 +5,6 @@ Ported to CodeMirror by Peter Kroon
.cm-s-lesser-dark {
line-height: 1.3em;
}
-.cm-s-lesser-dark {
- font-family: 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', 'Monaco', Courier, monospace !important;
-}
-
.cm-s-lesser-dark.CodeMirror { background: #262626; color: #EBEFE7; text-shadow: 0 -1px 1px #262626; }
.cm-s-lesser-dark div.CodeMirror-selected {background: #45443B !important;} /* 33322B*/
.cm-s-lesser-dark .CodeMirror-cursor { border-left: 1px solid white !important; }
diff --git a/theme/mdn-like.css b/theme/mdn-like.css
index c12cb1f94f..1e20b9e21b 100644
--- a/theme/mdn-like.css
+++ b/theme/mdn-like.css
@@ -7,7 +7,7 @@
The mdn-like theme is inspired on the displayed code examples at: https://developer.mozilla.org/en-US/docs/Web/CSS/animation
*/
-.cm-s-mdn-like.CodeMirror { color: #999; font-family: monospace; background-color: #fff; }
+.cm-s-mdn-like.CodeMirror { color: #999; background-color: #fff; }
.cm-s-mdn-like .CodeMirror-selected { background: #cfc !important; }
.cm-s-mdn-like .CodeMirror-gutters { background: #f8f8f8; border-left: 6px solid rgba(0,83,159,0.65); color: #333; }
diff --git a/theme/pastel-on-dark.css b/theme/pastel-on-dark.css
index df95699a01..72a247527e 100644
--- a/theme/pastel-on-dark.css
+++ b/theme/pastel-on-dark.css
@@ -11,7 +11,6 @@
background: #2c2827;
color: #8F938F;
line-height: 1.5;
- font-family: consolas, Courier, monospace;
font-size: 14px;
}
.cm-s-pastel-on-dark div.CodeMirror-selected { background: rgba(221,240,255,0.2) !important; }
diff --git a/theme/rubyblue.css b/theme/rubyblue.css
index b556139d7e..47fae0da9d 100644
--- a/theme/rubyblue.css
+++ b/theme/rubyblue.css
@@ -1,5 +1,3 @@
-.cm-s-rubyblue { font-family: Trebuchet, Verdana, sans-serif; } /* - customized editor font - */
-
.cm-s-rubyblue.CodeMirror { background: #112435; color: white; }
.cm-s-rubyblue div.CodeMirror-selected { background: #38566F !important; }
.cm-s-rubyblue .CodeMirror-gutters { background: #1F4661; border-right: 7px solid #3E7087; }
diff --git a/theme/solarized.css b/theme/solarized.css
index c9c84097d0..39fc83d7cd 100644
--- a/theme/solarized.css
+++ b/theme/solarized.css
@@ -29,7 +29,6 @@ http://ethanschoonover.com/solarized/img/solarized-palette.png
.cm-s-solarized {
line-height: 1.45em;
- font-family: Menlo,Monaco,"Andale Mono","lucida console","Courier New",monospace !important;
color-profile: sRGB;
rendering-intent: auto;
}
From 87036ed9bb356d09e4ef20cc4ed270d9dfbb983b Mon Sep 17 00:00:00 2001
From: as3boyan
Date: Mon, 31 Mar 2014 01:08:42 +0300
Subject: [PATCH 066/127] [haxe mode] Add 'abstract' keyword
---
mode/haxe/haxe.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mode/haxe/haxe.js b/mode/haxe/haxe.js
index d7ed7e6568..b8f8408d14 100644
--- a/mode/haxe/haxe.js
+++ b/mode/haxe/haxe.js
@@ -26,7 +26,7 @@ CodeMirror.defineMode("haxe", function(config, parserConfig) {
"function": kw("function"), "catch": kw("catch"), "untyped": kw("untyped"), "callback": kw("cb"),
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
"in": operator, "never": kw("property_access"), "trace":kw("trace"),
- "class": type, "enum":type, "interface":type, "typedef":type, "extends":type, "implements":type, "dynamic":type,
+ "class": type, "abstract":type, "enum":type, "interface":type, "typedef":type, "extends":type, "implements":type, "dynamic":type,
"true": atom, "false": atom, "null": atom
};
}();
From 58a75ce53780a3e7dcb3ee257545b08cad92c710 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Tue, 1 Apr 2014 17:57:11 +0200
Subject: [PATCH 067/127] Round top/bottom coords when drawing selection
To prevent gaps when browsers interpret fractional numbers oddly.
---
lib/codemirror.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lib/codemirror.js b/lib/codemirror.js
index 265879dbad..0356766aed 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -1279,6 +1279,8 @@
function add(left, top, width, bottom) {
if (top < 0) top = 0;
+ top = Math.round(top);
+ bottom = Math.round(bottom);
fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left +
"px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) +
"px; height: " + (bottom - top) + "px"));
From 12be7a0cdbef9d51f490b64af2a689f845501436 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Tue, 1 Apr 2014 17:58:04 +0200
Subject: [PATCH 068/127] Use more meaningful names for drawSelection*
functions
---
lib/codemirror.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/lib/codemirror.js b/lib/codemirror.js
index 0356766aed..ae7f5f4cc7 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -1231,9 +1231,9 @@
var range = doc.sel.ranges[i];
var collapsed = range.empty();
if (collapsed || cm.options.showCursorWhenSelecting)
- updateSelectionCursor(cm, range, curFragment);
+ drawSelectionCursor(cm, range, curFragment);
if (!collapsed)
- updateSelectionRange(cm, range, selFragment);
+ drawSelectionRange(cm, range, selFragment);
}
// Move the hidden textarea near the cursor to prevent scrolling artifacts
@@ -1253,7 +1253,7 @@
}
// Draws a cursor for the given range
- function updateSelectionCursor(cm, range, output) {
+ function drawSelectionCursor(cm, range, output) {
var pos = cursorCoords(cm, range.head, "div");
var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
@@ -1272,7 +1272,7 @@
}
// Draws the given range as a highlighted selection
- function updateSelectionRange(cm, range, output) {
+ function drawSelectionRange(cm, range, output) {
var display = cm.display, doc = cm.doc;
var fragment = document.createDocumentFragment();
var padding = paddingH(cm.display), leftSide = padding.left, rightSide = display.lineSpace.offsetWidth - padding.right;
From 5b085aea17121919d8caaa0794d1bea1b453fb2a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Radek=20Pi=C3=B3rkowski?=
Date: Tue, 1 Apr 2014 02:09:47 +0200
Subject: [PATCH 069/127] [closebracket addon] Fix: Trigger auto-close-triple
behaviour after exactly 3 quotes.
Issue #2385
---
addon/edit/closebrackets.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/addon/edit/closebrackets.js b/addon/edit/closebrackets.js
index 6cabed6eca..3cea887d1d 100644
--- a/addon/edit/closebrackets.js
+++ b/addon/edit/closebrackets.js
@@ -69,7 +69,8 @@
else
curType = "skip";
} else if (left == right && cur.ch > 1 &&
- cm.getRange(Pos(cur.line, cur.ch - 2), cur) == left + left)
+ cm.getRange(Pos(cur.line, cur.ch - 2), cur) == left + left &&
+ (cur.ch <= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != left))
curType = "addFour";
else if (left == right && CodeMirror.isWordChar(next))
return CodeMirror.Pass;
From b1bc7bac1f8707aa2e3f07cf775f9df3da20e6d8 Mon Sep 17 00:00:00 2001
From: Jan Keromnes
Date: Tue, 1 Apr 2014 00:39:41 +0000
Subject: [PATCH 070/127] Better looking SVG badges in README.md.
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 61f6b64525..6a0011b6be 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# CodeMirror
-[](http://travis-ci.org/marijnh/CodeMirror)
-[](http://badge.fury.io/js/codemirror)
+[](https://travis-ci.org/marijnh/CodeMirror)
+[](https://www.npmjs.org/package/codemirror)
CodeMirror is a JavaScript component that provides a code editor in
the browser. When a mode is available for the language you are coding
From 75e8f5278f502b66b7ba47f01ee3b52fd715fdcf Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Tue, 1 Apr 2014 18:29:53 +0200
Subject: [PATCH 071/127] [xml-hint addon] Support attributes that apply to all
tags
---
addon/hint/xml-hint.js | 11 ++++++++++-
demo/xmlcomplete.html | 4 ++++
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/addon/hint/xml-hint.js b/addon/hint/xml-hint.js
index fc025a2ded..9ebec05344 100644
--- a/addon/hint/xml-hint.js
+++ b/addon/hint/xml-hint.js
@@ -46,7 +46,16 @@
} else {
// Attribute completion
var curTag = tags[inner.state.tagName], attrs = curTag && curTag.attrs;
- if (!attrs) return;
+ var globalAttrs = tags["!attrs"];
+ if (!attrs && !globalAttrs) return;
+ if (!attrs) {
+ attrs = globalAttrs;
+ } else if (globalAttrs) { // Combine tag-local and global attributes
+ var set = {};
+ for (var nm in globalAttrs) if (globalAttrs.hasOwnProperty(nm)) set[nm] = globalAttrs[nm];
+ for (var nm in attrs) if (attrs.hasOwnProperty(nm)) set[nm] = attrs[nm];
+ attrs = set;
+ }
if (token.type == "string" || token.string == "=") { // A value
var before = cm.getRange(Pos(cur.line, Math.max(0, cur.ch - 60)),
Pos(cur.line, token.type == "string" ? token.start : token.end));
diff --git a/demo/xmlcomplete.html b/demo/xmlcomplete.html
index 2f81c54cf0..dea23adf84 100644
--- a/demo/xmlcomplete.html
+++ b/demo/xmlcomplete.html
@@ -52,6 +52,10 @@
var tags = {
"!top": ["top"],
+ "!attrs": {
+ id: null,
+ class: ["A", "B", "C"]
+ },
top: {
attrs: {
lang: ["en", "de", "fr", "nl"],
From 81b81d8f9b6d1deaaa1435553316aa6c887741b3 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Tue, 1 Apr 2014 21:22:41 +0200
Subject: [PATCH 072/127] Support electricInput as well as electricChars on
mode objects
Issue #2412
---
doc/manual.html | 18 +++++++++++++-----
lib/codemirror.js | 16 +++++++++++-----
mode/xml/xml.js | 2 +-
3 files changed, 25 insertions(+), 11 deletions(-)
diff --git a/doc/manual.html b/doc/manual.html
index 3d67530393..1279fcadd4 100644
--- a/doc/manual.html
+++ b/doc/manual.html
@@ -2804,12 +2804,20 @@ Static properties
continued lines in a block comment). All of these are
optional.
- Finally, a mode may define
- an electricChars property, which should hold a string
- containing all the characters that should trigger the behaviour
- described for
+
Finally, a mode may define either
+ an electricChars or an electricInput
+ property, which are used to automatically reindent the line when
+ certain patterns are typed and
the electricChars
- option.
+ option is enabled. electricChars may be a string, and
+ will trigger a reindent whenever one of the characters in that
+ string are typed. Often, it is more appropriate to
+ use electricInput, which should hold a regular
+ expression, and will trigger indentation when the part of the
+ line before the cursor matches the expression. It should
+ usually end with a $ character, so that it only
+ matches when the indentation-changing pattern was just typed, not when something was
+ typed after the pattern.
So, to summarize, a mode must provide
a token method, and it may
diff --git a/lib/codemirror.js b/lib/codemirror.js
index ae7f5f4cc7..41bf2e6658 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -2253,12 +2253,18 @@
if (inserted && !cm.state.pasteIncoming && cm.options.electricChars &&
cm.options.smartIndent && range.head.ch < 100 &&
(!i || doc.sel.ranges[i - 1].head.line != range.head.line)) {
- var electric = cm.getModeAt(range.head).electricChars;
- if (electric) for (var j = 0; j < electric.length; j++)
- if (inserted.indexOf(electric.charAt(j)) > -1) {
+ var mode = cm.getModeAt(range.head);
+ if (mode.electricChars) {
+ for (var j = 0; j < mode.electricChars.length; j++)
+ if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
+ indentLine(cm, range.head.line, "smart");
+ break;
+ }
+ } else if (mode.electricInput) {
+ var end = changeEnd(changeEvent);
+ if (mode.electricInput.test(getLine(doc, end.line).text.slice(0, end.ch)))
indentLine(cm, range.head.line, "smart");
- break;
- }
+ }
}
}
ensureCursorVisible(cm);
diff --git a/mode/xml/xml.js b/mode/xml/xml.js
index c626ce2b9a..3fc0cb5056 100644
--- a/mode/xml/xml.js
+++ b/mode/xml/xml.js
@@ -361,7 +361,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
else return 0;
},
- electricChars: "/",
+ electricInput: /<\/[\s\w:]+>$/,
blockCommentStart: "",
From ee9f33b981a49d02beeed2243bb7006342e5cc44 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Wed, 2 Apr 2014 16:08:02 +0200
Subject: [PATCH 073/127] [xml-hint addon] Filter out !attrs from top level
completions
---
addon/hint/xml-hint.js | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/addon/hint/xml-hint.js b/addon/hint/xml-hint.js
index 9ebec05344..9cfd1e884f 100644
--- a/addon/hint/xml-hint.js
+++ b/addon/hint/xml-hint.js
@@ -38,8 +38,9 @@
for (var i = 0; i < childList.length; ++i) if (!prefix || childList[i].lastIndexOf(prefix, 0) == 0)
result.push("<" + childList[i]);
} else if (tagType != "close") {
- for (var name in tags) if (tags.hasOwnProperty(name) && name != "!top" && (!prefix || name.lastIndexOf(prefix, 0) == 0))
- result.push("<" + name);
+ for (var name in tags)
+ if (tags.hasOwnProperty(name) && name != "!top" && name != "!attrs" && (!prefix || name.lastIndexOf(prefix, 0) == 0))
+ result.push("<" + name);
}
if (cx && (!prefix || tagType == "close" && cx.tagName.lastIndexOf(prefix, 0) == 0))
result.push("" + cx.tagName + ">");
From 91e02be407d8ccff5928d2b9ad4f590b803ca321 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Thu, 3 Apr 2014 11:31:40 +0200
Subject: [PATCH 074/127] Work around Webkit bug where sometimes the sizer gets
the wrong width
(It'll leave space for a scrollbar to the right of the sizer, though the
scroller does not actually have a scrollbar.)
Issue #2420
---
lib/codemirror.js | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/lib/codemirror.js b/lib/codemirror.js
index 41bf2e6658..ea58167227 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -652,6 +652,13 @@
function setDocumentHeight(cm, measure) {
cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = measure.docHeight + "px";
cm.display.gutters.style.height = Math.max(measure.docHeight, measure.clientHeight - scrollerCutOff) + "px";
+ // Work around Webkit bug where it sometimes reserves space for a
+ // non-existing phantom scrollbar in the scroller (Issue #2420)
+ if (webkit && cm.options.lineWrapping &&
+ cm.display.sizer.offsetWidth + cm.display.gutters.offsetWidth < cm.display.scroller.clientWidth - 1) {
+ cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = "0px";
+ cm.display.gutters.style.height = measure.docHeight + "px";
+ }
}
// Read the actual heights of the rendered lines, and update their
From 17a9de99ed61dbcc78fc54bc77bfe5b4ea140e9f Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Thu, 3 Apr 2014 11:32:13 +0200
Subject: [PATCH 075/127] Set forceUpdate flag in refresh method
Closes #2431
---
lib/codemirror.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/codemirror.js b/lib/codemirror.js
index ea58167227..2e7735bb4f 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -4214,6 +4214,7 @@
refresh: methodOp(function() {
var oldHeight = this.display.cachedTextHeight;
regChange(this);
+ this.curOp.forceUpdate = true;
clearCaches(this);
this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop);
updateGutterSpace(this);
From 6b8ddd012f0d10f18f59355ee5bd5bc6c8e58457 Mon Sep 17 00:00:00 2001
From: Doug Wikle
Date: Fri, 7 Mar 2014 09:01:19 -0500
Subject: [PATCH 076/127] [verilog mode] Rewrite
---
mode/index.html | 2 +-
mode/meta.js | 1 +
mode/verilog/index.html | 190 ++++++++++++++---------------
mode/verilog/test.js | 114 ++++++++++++++++++
mode/verilog/verilog.js | 315 ++++++++++++++++++++++++++++++++++++------------
test/index.html | 2 +
6 files changed, 444 insertions(+), 180 deletions(-)
create mode 100644 mode/verilog/test.js
diff --git a/mode/index.html b/mode/index.html
index 8b043b9cfc..4dc5fea180 100644
--- a/mode/index.html
+++ b/mode/index.html
@@ -108,7 +108,7 @@
VB.NET
VBScript
Velocity
- Verilog
+ Verilog/SystemVerilog
XML/HTML
XQuery
YAML
diff --git a/mode/meta.js b/mode/meta.js
index bada12c712..b8bfebda2e 100644
--- a/mode/meta.js
+++ b/mode/meta.js
@@ -89,6 +89,7 @@ CodeMirror.modeInfo = [
{name: 'MariaDB', mime: 'text/x-mariadb', mode: 'sql'},
{name: 'sTeX', mime: 'text/x-stex', mode: 'stex'},
{name: 'LaTeX', mime: 'text/x-latex', mode: 'stex'},
+ {name: 'SystemVerilog', mime: 'text/x-systemverilog', mode: 'verilog'},
{name: 'Tcl', mime: 'text/x-tcl', mode: 'tcl'},
{name: 'TiddlyWiki ', mime: 'text/x-tiddlywiki', mode: 'tiddlywiki'},
{name: 'Tiki wiki', mime: 'text/tiki', mode: 'tiki'},
diff --git a/mode/verilog/index.html b/mode/verilog/index.html
index cc71056446..4c06cdaecf 100644
--- a/mode/verilog/index.html
+++ b/mode/verilog/index.html
@@ -1,13 +1,14 @@
-CodeMirror: Verilog mode
+CodeMirror: Verilog/SystemVerilog mode
+
-
+
@@ -18,115 +19,102 @@
-Verilog mode
-
-/* Verilog demo code */
+SystemVerilog mode
-module butterfly
- #(
- parameter WIDTH = 32,
- parameter MWIDTH = 1
- )
- (
- input wire clk,
- input wire rst_n,
- // m_in contains data that passes through this block with no change.
- input wire [MWIDTH-1:0] m_in,
- // The twiddle factor.
- input wire signed [WIDTH-1:0] w,
- // XA
- input wire signed [WIDTH-1:0] xa,
- // XB
- input wire signed [WIDTH-1:0] xb,
- // Set to 1 when new data is present on inputs.
- input wire x_nd,
- // delayed version of m_in.
- output reg [MWIDTH-1:0] m_out,
- // YA = XA + W*XB
- // YB = XA - W*XB
- output wire signed [WIDTH-1:0] ya,
- output wire signed [WIDTH-1:0] yb,
- output reg y_nd,
- output reg error
- );
+
+// Literals
+1'b0
+1'bx
+1'bz
+16'hDC78
+'hdeadbeef
+'b0011xxzz
+1234
+32'd5678
+3.4e6
+-128.7
- // Set wire to the real and imag parts for convenience.
- wire signed [WIDTH/2-1:0] xa_re;
- wire signed [WIDTH/2-1:0] xa_im;
- assign xa_re = xa[WIDTH-1:WIDTH/2];
- assign xa_im = xa[WIDTH/2-1:0];
- wire signed [WIDTH/2-1: 0] ya_re;
- wire signed [WIDTH/2-1: 0] ya_im;
- assign ya = {ya_re, ya_im};
- wire signed [WIDTH/2-1: 0] yb_re;
- wire signed [WIDTH/2-1: 0] yb_im;
- assign yb = {yb_re, yb_im};
+// Macro definition
+`define BUS_WIDTH = 8;
- // Delayed stuff.
- reg signed [WIDTH/2-1:0] xa_re_z;
- reg signed [WIDTH/2-1:0] xa_im_z;
- // Output of multiplier
- wire signed [WIDTH-1:0] xbw;
- wire signed [WIDTH/2-1:0] xbw_re;
- wire signed [WIDTH/2-1:0] xbw_im;
- assign xbw_re = xbw[WIDTH-1:WIDTH/2];
- assign xbw_im = xbw[WIDTH/2-1:0];
- // Do summing
- // I don't think we should get overflow here because of the
- // size of the twiddle factors.
- // If we do testing should catch it.
- assign ya_re = xa_re_z + xbw_re;
- assign ya_im = xa_im_z + xbw_im;
- assign yb_re = xa_re_z - xbw_re;
- assign yb_im = xa_im_z - xbw_im;
-
- // Create the multiply module.
- multiply_complex #(WIDTH) multiply_complex_0
- (.clk(clk),
- .rst_n(rst_n),
- .x(xb),
- .y(w),
- .z(xbw)
- );
+// Module definition
+module block(
+ input clk,
+ input rst_n,
+ input [`BUS_WIDTH-1:0] data_in,
+ output [`BUS_WIDTH-1:0] data_out
+);
+
+ always @(posedge clk or negedge rst_n) begin
- always @ (posedge clk)
- begin
- if (!rst_n)
- begin
- y_nd <= 1'b0;
- error <= 1'b0;
- end
- else
- begin
- // Set delay for x_nd_old and m.
- y_nd <= x_nd;
- m_out <= m_in;
- if (x_nd)
- begin
- xa_re_z <= xa_re/2;
- xa_im_z <= xa_im/2;
- end
- end
+ if (~rst_n) begin
+ data_out <= 8'b0;
+ end else begin
+ data_out <= data_in;
end
-
+
+ if (~rst_n)
+ data_out <= 8'b0;
+ else
+ data_out <= data_in;
+
+ if (~rst_n)
+ begin
+ data_out <= 8'b0;
+ end
+ else
+ begin
+ data_out <= data_in;
+ end
+
+ end
+
endmodule
-
-
+// Class definition
+class test;
+
+ /**
+ * Sum two integers
+ */
+ function int sum(int a, int b);
+ int result = a + b;
+ string msg = $sformatf("%d + %d = %d", a, b, result);
+ $display(msg);
+ return result;
+ endfunction
+
+ task delay(int num_cycles);
+ repeat(num_cycles) #1;
+ endtask
+
+endclass
+
+
- Simple mode that tries to handle Verilog-like languages as well as it
- can. Takes one configuration parameters: keywords, an
- object whose property names are the keywords in the language.
+
+
+
+Syntax highlighting and indentation for the Verilog and SystemVerilog languages (IEEE 1800).
+
Configuration options:
+
+ noIndentKeywords - List of keywords which should not cause identation to increase. E.g. ["package", "module"]. Default: None
+
+
- MIME types defined: text/x-verilog (Verilog code).
-
+MIME types defined: text/x-verilog and text/x-systemverilog.
+
diff --git a/mode/verilog/test.js b/mode/verilog/test.js
new file mode 100644
index 0000000000..6f5770b848
--- /dev/null
+++ b/mode/verilog/test.js
@@ -0,0 +1,114 @@
+(function() {
+ var mode = CodeMirror.getMode({indentUnit: 4}, "verilog");
+ function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
+
+ MT("Binary literals",
+ "[number 1'b0]",
+ "[number 1'b1]",
+ "[number 1'bx]",
+ "[number 1'bz]",
+ "[number 1'bX]",
+ "[number 1'bZ]",
+ "[number 1'B0]",
+ "[number 1'B1]",
+ "[number 1'Bx]",
+ "[number 1'Bz]",
+ "[number 1'BX]",
+ "[number 1'BZ]",
+ "[number 1'b0]",
+ "[number 1'b1]",
+ "[number 2'b01]",
+ "[number 2'bxz]",
+ "[number 2'b11]",
+ "[number 2'b10]",
+ "[number 2'b1Z]",
+ "[number 12'b0101_0101_0101]",
+ "[number 1'b 0]",
+ "[number 'b0101]"
+ );
+
+ MT("Octal literals",
+ "[number 3'o7]",
+ "[number 3'O7]",
+ "[number 3'so7]",
+ "[number 3'SO7]"
+ );
+
+ MT("Decimal literals",
+ "[number 0]",
+ "[number 1]",
+ "[number 7]",
+ "[number 123_456]",
+ "[number 'd33]",
+ "[number 8'd255]",
+ "[number 8'D255]",
+ "[number 8'sd255]",
+ "[number 8'SD255]",
+ "[number 32'd123]",
+ "[number 32 'd123]",
+ "[number 32 'd 123]"
+ );
+
+ MT("Hex literals",
+ "[number 4'h0]",
+ "[number 4'ha]",
+ "[number 4'hF]",
+ "[number 4'hx]",
+ "[number 4'hz]",
+ "[number 4'hX]",
+ "[number 4'hZ]",
+ "[number 32'hdc78]",
+ "[number 32'hDC78]",
+ "[number 32 'hDC78]",
+ "[number 32'h DC78]",
+ "[number 32 'h DC78]",
+ "[number 32'h44x7]",
+ "[number 32'hFFF?]"
+ );
+
+ MT("Real number literals",
+ "[number 1.2]",
+ "[number 0.1]",
+ "[number 2394.26331]",
+ "[number 1.2E12]",
+ "[number 1.2e12]",
+ "[number 1.30e-2]",
+ "[number 0.1e-0]",
+ "[number 23E10]",
+ "[number 29E-2]",
+ "[number 236.123_763_e-12]"
+ );
+
+ MT("Operators",
+ "[meta ^]"
+ );
+
+ MT("Keywords",
+ "[keyword logic]",
+ "[keyword logic] [variable foo]",
+ "[keyword reg] [variable abc]"
+ );
+
+ MT("Variables",
+ "[variable _leading_underscore]",
+ "[variable _if]",
+ "[number 12] [variable foo]",
+ "[variable foo] [number 14]"
+ );
+
+ MT("Tick defines",
+ "[def `FOO]",
+ "[def `foo]",
+ "[def `FOO_bar]"
+ );
+
+ MT("System calls",
+ "[meta $display]",
+ "[meta $vpi_printf]"
+ );
+
+ MT("Line comment", "[comment // Hello world]");
+
+
+
+})();
diff --git a/mode/verilog/verilog.js b/mode/verilog/verilog.js
index bc4fd4feee..d52ecea2a3 100644
--- a/mode/verilog/verilog.js
+++ b/mode/verilog/verilog.js
@@ -9,35 +9,141 @@
"use strict";
CodeMirror.defineMode("verilog", function(config, parserConfig) {
+
var indentUnit = config.indentUnit,
- keywords = parserConfig.keywords || {},
- blockKeywords = parserConfig.blockKeywords || {},
- atoms = parserConfig.atoms || {},
- hooks = parserConfig.hooks || {},
+ statementIndentUnit = parserConfig.statementIndentUnit || indentUnit,
+ dontAlignCalls = parserConfig.dontAlignCalls,
+ noIndentKeywords = parserConfig.noIndentKeywords || [],
multiLineStrings = parserConfig.multiLineStrings;
- var isOperatorChar = /[&|~> | >= | & | | | ^ | ^~ | ~^ | >> | << | >>> | <<<
+ | -> | <->
+ inc_or_dec_operator ::= ++ | --
+ unary_module_path_operator ::=
+ ! | ~ | & | ~& | | | ~| | ^ | ~^ | ^~
+ binary_module_path_operator ::=
+ == | != | && | || | & | | | ^ | ^~ | ~^
+ */
+ var isOperatorChar = /[\+\-\*\/!~&|^%=?:]/;
+ var isBracketChar = /[\[\]{}()]/;
+
+ var unsignedNumber = /\d[0-9_]*/;
+ var decimalLiteral = /\d*\s*'s?d\s*\d[0-9_]*/i;
+ var binaryLiteral = /\d*\s*'s?b\s*[xz01][xz01_]*/i;
+ var octLiteral = /\d*\s*'s?o\s*[xz0-7][xz0-7_]*/i;
+ var hexLiteral = /\d*\s*'s?h\s*[0-9a-fxz?][0-9a-fxz?_]*/i;
+ var realLiteral = /(\d[\d_]*(\.\d[\d_]*)?E-?[\d_]+)|(\d[\d_]*\.\d[\d_]*)/i;
+
+ var closingBracketOrWord = /^((\w+)|[)}\]])/;
+ var closingBracket = /[)}\]]/;
var curPunc;
+ var curKeyword;
+
+ // Block openings which are closed by a matching keyword in the form of ("end" + keyword)
+ // E.g. "task" => "endtask"
+ var blockKeywords = words(
+ "case checker class clocking config function generate group interface module package" +
+ "primitive program property specify sequence table task"
+ );
+
+ // Opening/closing pairs
+ var openClose = {};
+ for (var keyword in blockKeywords) {
+ openClose[keyword] = "end" + keyword;
+ }
+ openClose["begin"] = "end";
+ openClose["casex"] = "endcase";
+ openClose["casez"] = "endcase";
+ openClose["do" ] = "while";
+ openClose["fork" ] = "join;join_any;join_none";
+
+ for (var i in noIndentKeywords) {
+ var keyword = noIndentKeywords[i];
+ if (openClose[keyword]) {
+ openClose[keyword] = undefined;
+ }
+ }
+
+ var statementKeywords = words("always always_comb always_ff always_latch assert assign assume else for foreach forever if initial repeat while");
function tokenBase(stream, state) {
- var ch = stream.next();
- if (hooks[ch]) {
- var result = hooks[ch](stream, state);
- if (result !== false) return result;
+ var ch = stream.peek();
+ if (/[,;:\.]/.test(ch)) {
+ curPunc = stream.next();
+ return null;
+ }
+ if (isBracketChar.test(ch)) {
+ curPunc = stream.next();
+ return "bracket";
+ }
+ // Macros (tick-defines)
+ if (ch == '`') {
+ stream.next();
+ if (stream.eatWhile(/[\w\$_]/)) {
+ return "def";
+ } else {
+ return null;
+ }
+ }
+ // System calls
+ if (ch == '$') {
+ stream.next();
+ if (stream.eatWhile(/[\w\$_]/)) {
+ return "meta";
+ } else {
+ return null;
+ }
}
+ // Time literals
+ if (ch == '#') {
+ stream.next();
+ stream.eatWhile(/[\d_.]/);
+ return "def";
+ }
+ // Strings
if (ch == '"') {
+ stream.next();
state.tokenize = tokenString(ch);
return state.tokenize(stream, state);
}
- if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
- curPunc = ch;
- return null;
- }
- if (/[\d']/.test(ch)) {
- stream.eatWhile(/[\w\.']/);
- return "number";
- }
+ // Comments
if (ch == "/") {
+ stream.next();
if (stream.eat("*")) {
state.tokenize = tokenComment;
return tokenComment(stream, state);
@@ -46,19 +152,43 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) {
stream.skipToEnd();
return "comment";
}
+ stream.backUp(1);
+ }
+
+ // Numeric literals
+ if (stream.match(realLiteral) ||
+ stream.match(decimalLiteral) ||
+ stream.match(binaryLiteral) ||
+ stream.match(octLiteral) ||
+ stream.match(hexLiteral) ||
+ stream.match(unsignedNumber) ||
+ stream.match(realLiteral)) {
+ return "number";
}
- if (isOperatorChar.test(ch)) {
- stream.eatWhile(isOperatorChar);
- return "operator";
+
+ // Operators
+ if (stream.eatWhile(isOperatorChar)) {
+ return "meta";
}
- stream.eatWhile(/[\w\$_]/);
- var cur = stream.current();
- if (keywords.propertyIsEnumerable(cur)) {
- if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
- return "keyword";
+
+ // Keywords / plain variables
+ if (stream.eatWhile(/[\w\$_]/)) {
+ var cur = stream.current();
+ if (keywords[cur]) {
+ if (openClose[cur]) {
+ curPunc = "newblock";
+ }
+ if (statementKeywords[cur]) {
+ curPunc = "newstatement";
+ }
+ curKeyword = cur;
+ return "keyword";
+ }
+ return "variable";
}
- if (atoms.propertyIsEnumerable(cur)) return "atom";
- return "variable";
+
+ stream.next();
+ return null;
}
function tokenString(quote) {
@@ -94,18 +224,56 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) {
this.prev = prev;
}
function pushContext(state, col, type) {
- return state.context = new Context(state.indented, col, type, null, state.context);
+ var indent = state.indented;
+ var c = new Context(indent, col, type, null, state.context);
+ return state.context = c;
}
function popContext(state) {
var t = state.context.type;
- if (t == ")" || t == "]" || t == "}")
+ if (t == ")" || t == "]" || t == "}") {
state.indented = state.context.indented;
+ }
return state.context = state.context.prev;
}
- // Interface
+ function isClosing(text, contextClosing) {
+ if (text == contextClosing) {
+ return true;
+ } else {
+ // contextClosing may be mulitple keywords separated by ;
+ var closingKeywords = contextClosing.split(";");
+ for (var i in closingKeywords) {
+ if (text == closingKeywords[i]) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ function buildElectricInputRegEx() {
+ // Reindentation should occur on any bracket char: {}()[]
+ // or on a match of any of the block closing keywords, at
+ // the end of a line
+ var allClosings = [];
+ for (var i in openClose) {
+ if (openClose[i]) {
+ var closings = openClose[i].split(";");
+ for (var j in closings) {
+ allClosings.push(closings[j]);
+ }
+ }
+ }
+ var re = new RegExp("[{}()\\[\\]]|(" + allClosings.join("|") + ")$");
+ return re;
+ }
+ // Interface
return {
+
+ // Regex to force current line to reindent
+ electricInput: buildElectricInputRegEx(),
+
startState: function(basecolumn) {
return {
tokenize: null,
@@ -124,69 +292,60 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) {
}
if (stream.eatSpace()) return null;
curPunc = null;
+ curKeyword = null;
var style = (state.tokenize || tokenBase)(stream, state);
- if (style == "comment" || style == "meta") return style;
+ if (style == "comment" || style == "meta" || style == "variable") return style;
if (ctx.align == null) ctx.align = true;
- if ((curPunc == ";" || curPunc == ":") && ctx.type == "statement") popContext(state);
- else if (curPunc == "{") pushContext(state, stream.column(), "}");
- else if (curPunc == "[") pushContext(state, stream.column(), "]");
- else if (curPunc == "(") pushContext(state, stream.column(), ")");
- else if (curPunc == "}") {
- while (ctx.type == "statement") ctx = popContext(state);
- if (ctx.type == "}") ctx = popContext(state);
- while (ctx.type == "statement") ctx = popContext(state);
+ if (curPunc == ctx.type) {
+ popContext(state);
+ }
+ else if ((curPunc == ";" && ctx.type == "statement") ||
+ (ctx.type && isClosing(curKeyword, ctx.type))) {
+ ctx = popContext(state);
+ while (ctx && ctx.type == "statement") ctx = popContext(state);
}
- else if (curPunc == ctx.type) popContext(state);
- else if (ctx.type == "}" || ctx.type == "top" || (ctx.type == "statement" && curPunc == "newstatement"))
+ else if (curPunc == "{") { pushContext(state, stream.column(), "}"); }
+ else if (curPunc == "[") { pushContext(state, stream.column(), "]"); }
+ else if (curPunc == "(") { pushContext(state, stream.column(), ")"); }
+ else if (ctx && ctx.type == "endcase" && curPunc == ":") { pushContext(state, stream.column(), "statement"); }
+ else if (curPunc == "newstatement") {
pushContext(state, stream.column(), "statement");
+ } else if (curPunc == "newblock") {
+ var close = openClose[curKeyword];
+ pushContext(state, stream.column(), close);
+ }
+
state.startOfLine = false;
return style;
},
indent: function(state, textAfter) {
- if (state.tokenize != tokenBase && state.tokenize != null) return 0;
- var firstChar = textAfter && textAfter.charAt(0), ctx = state.context, closing = firstChar == ctx.type;
- if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : indentUnit);
- else if (ctx.align) return ctx.column + (closing ? 0 : 1);
+ if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass;
+ var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
+ if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev;
+ var closing = false;
+ var possibleClosing = textAfter.match(closingBracketOrWord);
+ if (possibleClosing) {
+ closing = isClosing(possibleClosing[0], ctx.type);
+ }
+ if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit);
+ else if (closingBracket.test(ctx.type) && ctx.align && !dontAlignCalls) return ctx.column + (closing ? 0 : 1);
+ else if (ctx.type == ")" && !closing) return ctx.indented + statementIndentUnit;
else return ctx.indented + (closing ? 0 : indentUnit);
},
- electricChars: "{}"
+ blockCommentStart: "/*",
+ blockCommentEnd: "*/",
+ lineComment: "//"
};
});
- function words(str) {
- var obj = {}, words = str.split(" ");
- for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
- return obj;
- }
-
- var verilogKeywords = "always and assign automatic begin buf bufif0 bufif1 case casex casez cell cmos config " +
- "deassign default defparam design disable edge else end endcase endconfig endfunction endgenerate endmodule " +
- "endprimitive endspecify endtable endtask event for force forever fork function generate genvar highz0 " +
- "highz1 if ifnone incdir include initial inout input instance integer join large liblist library localparam " +
- "macromodule medium module nand negedge nmos nor noshowcancelled not notif0 notif1 or output parameter pmos " +
- "posedge primitive pull0 pull1 pulldown pullup pulsestyle_onevent pulsestyle_ondetect rcmos real realtime " +
- "reg release repeat rnmos rpmos rtran rtranif0 rtranif1 scalared showcancelled signed small specify specparam " +
- "strong0 strong1 supply0 supply1 table task time tran tranif0 tranif1 tri tri0 tri1 triand trior trireg " +
- "unsigned use vectored wait wand weak0 weak1 while wire wor xnor xor";
-
- var verilogBlockKeywords = "begin bufif0 bufif1 case casex casez config else end endcase endconfig endfunction " +
- "endgenerate endmodule endprimitive endspecify endtable endtask for forever function generate if ifnone " +
- "macromodule module primitive repeat specify table task while";
-
- function metaHook(stream) {
- stream.eatWhile(/[\w\$_]/);
- return "meta";
- }
-
- CodeMirror.defineMIME("text/x-verilog", {
- name: "verilog",
- keywords: words(verilogKeywords),
- blockKeywords: words(verilogBlockKeywords),
- atoms: words("null"),
- hooks: {"`": metaHook, "$": metaHook}
- });
+CodeMirror.defineMIME("text/x-verilog", {
+ name: "verilog"
+});
+CodeMirror.defineMIME("text/x-systemverilog", {
+ name: "systemverilog"
+});
});
diff --git a/test/index.html b/test/index.html
index 4fcc028dce..76fd835f28 100644
--- a/test/index.html
+++ b/test/index.html
@@ -95,6 +95,8 @@
+
+
From 66b842d064a95f37047fe1823582df9285dd99a1 Mon Sep 17 00:00:00 2001
From: as3boyan
Date: Tue, 1 Apr 2014 23:03:46 +0300
Subject: [PATCH 077/127] [haxe mode] Support imports with wildcards
Haxe supports imports with willcard
http://haxe.org/manual/modules#import-whole-package
---
mode/haxe/haxe.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mode/haxe/haxe.js b/mode/haxe/haxe.js
index b8f8408d14..83224d86e4 100644
--- a/mode/haxe/haxe.js
+++ b/mode/haxe/haxe.js
@@ -316,7 +316,7 @@ CodeMirror.defineMode("haxe", function(config, parserConfig) {
function importdef (type, value) {
if(type == "variable" && /[A-Z]/.test(value.charAt(0))) { registerimport(value); return cont(); }
- else if(type == "variable" || type == "property" || type == ".") return cont(importdef);
+ else if(type == "variable" || type == "property" || type == "." || value == "*") return cont(importdef);
}
function typedef (type, value)
From 82fbd5d6f4acf0b81677ba937811f27b45bb6e29 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Mon, 7 Apr 2014 10:17:37 +0200
Subject: [PATCH 078/127] Throw an error when a tokenizer doesn't advance the
stream
Issue #2427
---
lib/codemirror.js | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/lib/codemirror.js b/lib/codemirror.js
index 2e7735bb4f..90b827365c 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -3882,7 +3882,7 @@
var stream = new StringStream(line.text, this.options.tabSize);
while (stream.pos < pos.ch && !stream.eol()) {
stream.start = stream.pos;
- var style = mode.token(stream, state);
+ var style = readToken(mode, stream, state);
}
return {start: stream.start,
end: stream.pos,
@@ -5548,6 +5548,13 @@
if (inner.mode.blankLine) return inner.mode.blankLine(inner.state);
}
+ function readToken(mode, stream, state) {
+ var style = mode.token(stream, state);
+ if (stream.pos <= stream.start)
+ throw new Error("Mode " + mode.name + " failed to advance stream.");
+ return style;
+ }
+
// Run the given mode's parser over a line, calling f for each token.
function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) {
var flattenSpans = mode.flattenSpans;
@@ -5562,7 +5569,7 @@
stream.pos = text.length;
style = null;
} else {
- style = extractLineClasses(mode.token(stream, state), lineClasses);
+ style = extractLineClasses(readToken(mode, stream, state), lineClasses);
}
if (cm.options.addModeClass) {
var mName = CodeMirror.innerMode(mode, state).mode.name;
@@ -5643,7 +5650,7 @@
stream.start = stream.pos = startAt || 0;
if (text == "") callBlankLine(mode, state);
while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) {
- mode.token(stream, state);
+ readToken(mode, stream, state);
stream.start = stream.pos;
}
}
From 264ae319a31af6d79846c570a35fddb4413be6e2 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Mon, 7 Apr 2014 11:01:36 +0200
Subject: [PATCH 079/127] [javascript mode] Improve indentation of hanging else
clauses
Closes #2429
---
mode/javascript/javascript.js | 10 +++++++---
mode/javascript/test.js | 16 ++++++++++++++++
2 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js
index c45e04bb8c..9318aabe99 100644
--- a/mode/javascript/javascript.js
+++ b/mode/javascript/javascript.js
@@ -325,7 +325,11 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
if (type == "{") return cont(pushlex("}"), block, poplex);
if (type == ";") return cont();
- if (type == "if") return cont(pushlex("form"), expression, statement, poplex, maybeelse);
+ if (type == "if") {
+ if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
+ cx.state.cc.pop()();
+ return cont(pushlex("form"), expression, statement, poplex, maybeelse);
+ }
if (type == "function") return cont(functiondef);
if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
if (type == "variable") return cont(pushlex("stat"), maybelabel);
@@ -493,7 +497,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (type == ",") return cont(vardef);
}
function maybeelse(type, value) {
- if (type == "keyword b" && value == "else") return cont(pushlex("form"), statement, poplex);
+ if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
}
function forspec(type) {
if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
@@ -606,7 +610,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (state.tokenize != tokenBase) return 0;
var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
// Kludge to prevent 'maybelse' from blocking lexical scope pops
- for (var i = state.cc.length - 1; i >= 0; --i) {
+ if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
var c = state.cc[i];
if (c == poplex) lexical = lexical.prev;
else if (c != maybeelse) break;
diff --git a/mode/javascript/test.js b/mode/javascript/test.js
index 3f73196118..36341862f0 100644
--- a/mode/javascript/test.js
+++ b/mode/javascript/test.js
@@ -104,6 +104,22 @@
" [keyword debugger];",
"}");
+ MT("indent_else",
+ "[keyword for] (;;)",
+ " [keyword if] ([variable foo])",
+ " [keyword if] ([variable bar])",
+ " [number 1];",
+ " [keyword else]",
+ " [number 2];",
+ " [keyword else]",
+ " [number 3];");
+
+ MT("indent_below_if",
+ "[keyword for] (;;)",
+ " [keyword if] ([variable foo])",
+ " [number 1];",
+ "[number 2];");
+
MT("multilinestring",
"[keyword var] [variable x] [operator =] [string 'foo\\]",
"[string bar'];");
From a1432781943d8499e76f8f7e51124747b1ea54b3 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Mon, 7 Apr 2014 11:10:06 +0200
Subject: [PATCH 080/127] Fix extra layout round-trip introduced by fix for
issue #2420
---
lib/codemirror.js | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/lib/codemirror.js b/lib/codemirror.js
index 90b827365c..a37c921391 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -547,6 +547,8 @@
updateSelection(cm);
setDocumentHeight(cm, barMeasure);
updateScrollbars(cm, barMeasure);
+ if (webkit && cm.options.lineWrapping)
+ checkForWebkitWidthBug(cm, barMeasure); // (Issue #2420)
if (first && cm.options.lineWrapping && oldWidth != cm.display.scroller.clientWidth) {
forced = true;
continue;
@@ -652,10 +654,13 @@
function setDocumentHeight(cm, measure) {
cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = measure.docHeight + "px";
cm.display.gutters.style.height = Math.max(measure.docHeight, measure.clientHeight - scrollerCutOff) + "px";
+ }
+
+
+ function checkForWebkitWidthBug(cm, measure) {
// Work around Webkit bug where it sometimes reserves space for a
// non-existing phantom scrollbar in the scroller (Issue #2420)
- if (webkit && cm.options.lineWrapping &&
- cm.display.sizer.offsetWidth + cm.display.gutters.offsetWidth < cm.display.scroller.clientWidth - 1) {
+ if (cm.display.sizer.offsetWidth + cm.display.gutters.offsetWidth < cm.display.scroller.clientWidth - 1) {
cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = "0px";
cm.display.gutters.style.height = measure.docHeight + "px";
}
From e496a0d880a2e0f18af79d7cb081fae544c0fb79 Mon Sep 17 00:00:00 2001
From: mauricio
Date: Thu, 3 Apr 2014 23:12:26 -0300
Subject: [PATCH 081/127] [xml mode] Fix closing tag regexp
---
mode/xml/xml.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mode/xml/xml.js b/mode/xml/xml.js
index 3fc0cb5056..b8c4297976 100644
--- a/mode/xml/xml.js
+++ b/mode/xml/xml.js
@@ -334,7 +334,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
return state.tagStart + indentUnit * multilineTagIndentFactor;
}
if (alignCDATA && /
Date: Mon, 7 Apr 2014 11:20:38 +0200
Subject: [PATCH 082/127] [merge addon] Verify that diff is up to date in
left/rightChunks
Issue #2438
---
addon/merge/merge.js | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/addon/merge/merge.js b/addon/merge/merge.js
index fc1cb2f5a1..c8619e7394 100644
--- a/addon/merge/merge.js
+++ b/addon/merge/merge.js
@@ -53,6 +53,14 @@
}
};
+ function ensureDiff(dv) {
+ if (dv.diffOutOfDate) {
+ dv.diff = getDiff(dv.orig.getValue(), dv.edit.getValue());
+ dv.diffOutOfDate = false;
+ CodeMirror.signal(dv.edit, "updateDiff", dv.diff);
+ }
+ }
+
function registerUpdate(dv) {
var edit = {from: 0, to: 0, marked: []};
var orig = {from: 0, to: 0, marked: []};
@@ -65,11 +73,7 @@
clearMarks(dv.orig, orig.marked, dv.classes);
edit.from = edit.to = orig.from = orig.to = 0;
}
- if (dv.diffOutOfDate) {
- dv.diff = getDiff(dv.orig.getValue(), dv.edit.getValue());
- dv.diffOutOfDate = false;
- CodeMirror.signal(dv.edit, "updateDiff", dv.diff);
- }
+ ensureDiff(dv);
if (dv.showDifferences) {
updateMarks(dv.edit, dv.diff, edit, DIFF_INSERT, dv.classes);
updateMarks(dv.orig, dv.diff, orig, DIFF_DELETE, dv.classes);
@@ -362,10 +366,10 @@
if (this.left) this.left.setShowDifferences(val);
},
rightChunks: function() {
- return this.right && getChunks(this.right.diff);
+ return this.right && getChunks(this.right);
},
leftChunks: function() {
- return this.left && getChunks(this.left.diff);
+ return this.left && getChunks(this.left);
}
};
@@ -416,9 +420,10 @@
f(startOrig, orig.line + 1, startEdit, edit.line + 1);
}
- function getChunks(diff) {
+ function getChunks(dv) {
+ ensureDiff(dv);
var collect = [];
- iterateChunks(diff, function(topOrig, botOrig, topEdit, botEdit) {
+ iterateChunks(dv.diff, function(topOrig, botOrig, topEdit, botEdit) {
collect.push({origFrom: topOrig, origTo: botOrig,
editFrom: topEdit, editTo: botEdit});
});
From 72f00862d3487bc76c07a987ef7a9dce3365c26e Mon Sep 17 00:00:00 2001
From: Vincent Woo
Date: Sun, 6 Apr 2014 15:09:30 -0700
Subject: [PATCH 083/127] [r mode] Add lineComment property
---
mode/r/r.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/mode/r/r.js b/mode/r/r.js
index 7f4feb238b..281d7fa40f 100644
--- a/mode/r/r.js
+++ b/mode/r/r.js
@@ -148,7 +148,9 @@ CodeMirror.defineMode("r", function(config) {
if (ctx.type == "block") return ctx.indent + (firstChar == "{" ? 0 : config.indentUnit);
else if (ctx.align) return ctx.column + (closing ? 0 : 1);
else return ctx.indent + (closing ? 0 : config.indentUnit);
- }
+ },
+
+ lineComment: "#"
};
});
From 1eafe973de552c1c70163d3fa60ce23e2d1952ba Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Mon, 7 Apr 2014 16:10:51 +0200
Subject: [PATCH 084/127] List punctuation in default theme, don't set color
for default color styles
Also fix Erlang mode to not return a non-standard token type.
Issue #2435
---
lib/codemirror.css | 7 ++++---
mode/erlang/erlang.js | 2 +-
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/lib/codemirror.css b/lib/codemirror.css
index 13eb137918..098a317a22 100644
--- a/lib/codemirror.css
+++ b/lib/codemirror.css
@@ -70,11 +70,12 @@ div.CodeMirror-overwrite div.CodeMirror-cursor {}
.cm-s-default .cm-atom {color: #219;}
.cm-s-default .cm-number {color: #164;}
.cm-s-default .cm-def {color: #00f;}
-.cm-s-default .cm-variable {color: black;}
+.cm-s-default .cm-variable,
+.cm-s-default .cm-punctuation,
+.cm-s-default .cm-property,
+.cm-s-default .cm-operator {}
.cm-s-default .cm-variable-2 {color: #05a;}
.cm-s-default .cm-variable-3 {color: #085;}
-.cm-s-default .cm-property {color: black;}
-.cm-s-default .cm-operator {color: black;}
.cm-s-default .cm-comment {color: #a50;}
.cm-s-default .cm-string {color: #a11;}
.cm-s-default .cm-string-2 {color: #f50;}
diff --git a/mode/erlang/erlang.js b/mode/erlang/erlang.js
index 79693fca22..3d4b1ba92e 100644
--- a/mode/erlang/erlang.js
+++ b/mode/erlang/erlang.js
@@ -358,7 +358,7 @@ CodeMirror.defineMode("erlang", function(cmCfg) {
switch (type) {
case "atom": return "atom";
case "attribute": return "attribute";
- case "boolean": return "special";
+ case "boolean": return "atom";
case "builtin": return "builtin";
case "close_paren": return null;
case "colon": return null;
From 3be0f06e00f1afc0868b5d52a68214dc236ea3b4 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Mon, 7 Apr 2014 21:29:43 +0200
Subject: [PATCH 085/127] [rulers addon] Fix bug where rulers cause unnecessary
vertical scroll
Issue #2439
---
addon/display/rulers.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/addon/display/rulers.js b/addon/display/rulers.js
index eb0ff06e3a..a5386aa510 100644
--- a/addon/display/rulers.js
+++ b/addon/display/rulers.js
@@ -31,7 +31,7 @@
var val = cm.getOption("rulers");
var cw = cm.defaultCharWidth();
var left = cm.charCoords(CodeMirror.Pos(cm.firstLine(), 0), "div").left;
- var bot = -cm.display.scroller.offsetHeight;
+ var minH = cm.display.scroller.offsetHeight + 30;
for (var i = 0; i < val.length; i++) {
var elt = document.createElement("div");
var col, cls = null;
@@ -42,7 +42,7 @@
cls = val[i].className;
}
elt.className = "CodeMirror-ruler" + (cls ? " " + cls : "");
- elt.style.cssText = "left: " + (left + col * cw) + "px; top: -50px; bottom: " + bot + "px";
+ elt.style.cssText = "left: " + (left + col * cw) + "px; top: -50px; bottom: -20px; min-height: " + minH + "px";
cm.display.lineSpace.insertBefore(elt, cm.display.cursorDiv);
}
}
From df33eaf3b7cc3c9cffe42e6276564b837528d66d Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Mon, 7 Apr 2014 21:50:57 +0200
Subject: [PATCH 086/127] [markdown mode] Fix for token sometimes not advancing
the stream
Issue #2447
---
mode/markdown/markdown.js | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js
index 199c7a7155..ff466be86f 100644
--- a/mode/markdown/markdown.js
+++ b/mode/markdown/markdown.js
@@ -709,7 +709,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
if (forceBlankLine) {
state.prevLineHasContent = false;
- return blankLine(state);
+ blankLine(state);
+ return this.token(stream, state);
} else {
state.prevLineHasContent = state.thisLineHasContent;
state.thisLineHasContent = true;
@@ -737,7 +738,9 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
state.indentation = adjustedIndentation;
if (indentation > 0) return null;
}
- return state.f(stream, state);
+ var result = state.f(stream, state);
+ if (stream.start == stream.pos) return this.token(stream, state);
+ else return result;
},
innerMode: function(state) {
From 72f0e188def243041e4e748a193c29f5b38d660b Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Mon, 7 Apr 2014 21:51:20 +0200
Subject: [PATCH 087/127] Add check for stream advancement to mode test runner
Issue #2447
---
test/mode_test.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/test/mode_test.js b/test/mode_test.js
index 46174e1f78..dc20a0523e 100644
--- a/test/mode_test.js
+++ b/test/mode_test.js
@@ -120,6 +120,8 @@
/* Start copied code from CodeMirror.highlight */
while (!stream.eol()) {
var compare = mode.token(stream, state), substr = stream.current();
+ if (stream.start >= stream.pos)
+ throw new Failure("Failed to advance the stream." + stream.string + " " + stream.pos);
if (compare && compare.indexOf(" ") > -1) compare = compare.split(' ').sort().join(' ');
stream.start = stream.pos;
if (pos && st[pos-2] == compare && !newLine) {
From a97d436143f0346091fd391f4d682e30ab206437 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Mon, 7 Apr 2014 21:58:46 +0200
Subject: [PATCH 088/127] [haml mode] Fix tokenizer not advancing stream when
switching modes
---
mode/haml/haml.js | 11 +++--------
1 file changed, 3 insertions(+), 8 deletions(-)
diff --git a/mode/haml/haml.js b/mode/haml/haml.js
index 6b205b43e4..59a86e7cec 100644
--- a/mode/haml/haml.js
+++ b/mode/haml/haml.js
@@ -8,9 +8,6 @@
})(function(CodeMirror) {
"use strict";
-(function() {
- "use strict";
-
// full haml mode. This handled embeded ruby and html fragments too
CodeMirror.defineMode("haml", function(config) {
var htmlMode = CodeMirror.getMode(config, {name: "htmlmixed"});
@@ -75,7 +72,7 @@
// donot handle --> as valid ruby, make it HTML close comment instead
if (state.startOfLine && !stream.match("-->", false) && (ch == "=" || ch == "-" )) {
state.tokenize = ruby;
- return null;
+ return state.tokenize(stream, state);
}
if (state.previousToken.style == "hamlTag" ||
@@ -83,10 +80,10 @@
state.previousToken.style == "hamlAttribute") {
if (ch == "(") {
state.tokenize = rubyInQuote(")");
- return null;
+ return state.tokenize(stream, state);
} else if (ch == "{") {
state.tokenize = rubyInQuote("}");
- return null;
+ return state.tokenize(stream, state);
}
}
@@ -156,6 +153,4 @@
}, "htmlmixed", "ruby");
CodeMirror.defineMIME("text/x-haml", "haml");
-})();
-
});
From 90e0c283f7ba61f45b3c9d632de98a1c9a7ce538 Mon Sep 17 00:00:00 2001
From: B Krishna Chaitanya
Date: Tue, 8 Apr 2014 00:53:20 +0530
Subject: [PATCH 089/127] [sublime keymap] Keep cursor in view while scrolling
with Ctrl+Up or Ctrl+Down
---
keymap/sublime.js | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/keymap/sublime.js b/keymap/sublime.js
index 4d9211533e..ae33d48d5a 100644
--- a/keymap/sublime.js
+++ b/keymap/sublime.js
@@ -52,9 +52,23 @@
cmds[map["Alt-Right"] = "goSubwordRight"] = function(cm) { moveSubword(cm, 1); };
cmds[map[ctrl + "Up"] = "scrollLineUp"] = function(cm) {
+ if(!cm.somethingSelected()){
+ var visibleBottomLine = cm.lineAtHeight(cm.getScrollInfo().top + cm.getScrollInfo().clientHeight, "local");
+ var cur = cm.getCursor();
+ if(cur.line >= visibleBottomLine){
+ cm.setCursor({line:visibleBottomLine-1, ch:cur.ch});
+ }
+ }
cm.scrollTo(null, cm.getScrollInfo().top - cm.defaultTextHeight());
};
cmds[map[ctrl + "Down"] = "scrollLineDown"] = function(cm) {
+ if(!cm.somethingSelected()){
+ var visibleTopLine = cm.lineAtHeight(cm.getScrollInfo().top, "local")+1;
+ var cur = cm.getCursor();
+ if(cur.line-1 < visibleTopLine){
+ cm.setCursor({line:visibleTopLine+1, ch:cur.ch});
+ }
+ }
cm.scrollTo(null, cm.getScrollInfo().top + cm.defaultTextHeight());
};
From 0cb9b1daa7f40f9eb58e94a1520ad06fdb1446de Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Tue, 8 Apr 2014 08:50:25 +0200
Subject: [PATCH 090/127] Clean up 90e0c283f7ba61f45b3c9d632de98a1c9a7ce538
Issue #2448
---
keymap/sublime.js | 26 ++++++++++++--------------
1 file changed, 12 insertions(+), 14 deletions(-)
diff --git a/keymap/sublime.js b/keymap/sublime.js
index ae33d48d5a..eea46347fd 100644
--- a/keymap/sublime.js
+++ b/keymap/sublime.js
@@ -52,24 +52,22 @@
cmds[map["Alt-Right"] = "goSubwordRight"] = function(cm) { moveSubword(cm, 1); };
cmds[map[ctrl + "Up"] = "scrollLineUp"] = function(cm) {
- if(!cm.somethingSelected()){
- var visibleBottomLine = cm.lineAtHeight(cm.getScrollInfo().top + cm.getScrollInfo().clientHeight, "local");
- var cur = cm.getCursor();
- if(cur.line >= visibleBottomLine){
- cm.setCursor({line:visibleBottomLine-1, ch:cur.ch});
- }
+ var info = cm.getScrollInfo();
+ if (!cm.somethingSelected()) {
+ var visibleBottomLine = cm.lineAtHeight(info.top + info.clientHeight, "local");
+ if (cm.getCursor().line >= visibleBottomLine)
+ cm.execCommand("goLineUp");
}
- cm.scrollTo(null, cm.getScrollInfo().top - cm.defaultTextHeight());
+ cm.scrollTo(null, info.top - cm.defaultTextHeight());
};
cmds[map[ctrl + "Down"] = "scrollLineDown"] = function(cm) {
- if(!cm.somethingSelected()){
- var visibleTopLine = cm.lineAtHeight(cm.getScrollInfo().top, "local")+1;
- var cur = cm.getCursor();
- if(cur.line-1 < visibleTopLine){
- cm.setCursor({line:visibleTopLine+1, ch:cur.ch});
- }
+ var info = cm.getScrollInfo();
+ if (!cm.somethingSelected()) {
+ var visibleTopLine = cm.lineAtHeight(info.top, "local")+1;
+ if (cm.getCursor().line <= visibleTopLine)
+ cm.execCommand("goLineDown");
}
- cm.scrollTo(null, cm.getScrollInfo().top + cm.defaultTextHeight());
+ cm.scrollTo(null, info.top + cm.defaultTextHeight());
};
cmds[map["Shift-" + ctrl + "L"] = "splitSelectionByLine"] = function(cm) {
From d77a0440c3ed1d3ac5f5e2877346528c51330751 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Tue, 8 Apr 2014 10:29:38 +0200
Subject: [PATCH 091/127] [merge addon] Don't try to remove line class on lines
that aren't in doc anymore
Issue #2438
---
addon/merge/merge.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/addon/merge/merge.js b/addon/merge/merge.js
index c8619e7394..fe3fcf4282 100644
--- a/addon/merge/merge.js
+++ b/addon/merge/merge.js
@@ -169,7 +169,7 @@
var mark = arr[i];
if (mark instanceof CodeMirror.TextMarker) {
mark.clear();
- } else {
+ } else if (mark.parent) {
editor.removeLineClass(mark, "background", classes.chunk);
editor.removeLineClass(mark, "background", classes.start);
editor.removeLineClass(mark, "background", classes.end);
From aa90eb2f8c1bc5c73c6255ce7733b8cd351e0036 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Tue, 8 Apr 2014 10:37:19 +0200
Subject: [PATCH 092/127] [clike mode] Remove obsolete function namespace
---
mode/clike/clike.js | 2 --
1 file changed, 2 deletions(-)
diff --git a/mode/clike/clike.js b/mode/clike/clike.js
index 0e61020845..ff0c91d9fe 100644
--- a/mode/clike/clike.js
+++ b/mode/clike/clike.js
@@ -173,7 +173,6 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
};
});
-(function() {
function words(str) {
var obj = {}, words = str.split(" ");
for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
@@ -432,6 +431,5 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
hooks: {"#": cppHook},
modeProps: {fold: ["brace", "include"]}
});
-}());
});
From 3d5211dff75aabaab56f148a60d8fbaa14c29205 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Tue, 8 Apr 2014 10:39:42 +0200
Subject: [PATCH 093/127] [clike mode] Enable autocompletion in mode demo
---
mode/clike/index.html | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/mode/clike/index.html b/mode/clike/index.html
index d892fddbdb..d1abf9359d 100644
--- a/mode/clike/index.html
+++ b/mode/clike/index.html
@@ -7,6 +7,8 @@
+
+
@@ -185,6 +187,8 @@
matchBrackets: true,
mode: "text/x-java"
});
+ var mac = CodeMirror.keyMap.default == CodeMirror.keyMap.macDefault;
+ CodeMirror.keyMap.default[(mac ? "Cmd" : "Ctrl") + "-Space"] = "autocomplete";
Simple mode that tries to handle C-like languages as well as it
From 9fb57bc70bf5e339436984e03a1e376241b61e4f Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Tue, 8 Apr 2014 10:47:22 +0200
Subject: [PATCH 094/127] Add simple completion helper for php, scala, java, c#
Issue #2441
---
mode/clike/clike.js | 7 ++++---
mode/php/php.js | 23 +++++++++++++++--------
2 files changed, 19 insertions(+), 11 deletions(-)
diff --git a/mode/clike/clike.js b/mode/clike/clike.js
index ff0c91d9fe..60b88bf1aa 100644
--- a/mode/clike/clike.js
+++ b/mode/clike/clike.js
@@ -250,6 +250,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
}
function def(mimes, mode) {
+ if (typeof mimes == "string") mimes = [mimes];
var words = [];
function add(obj) {
if (obj) for (var prop in obj) if (obj.hasOwnProperty(prop))
@@ -294,7 +295,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
},
modeProps: {fold: ["brace", "include"]}
});
- CodeMirror.defineMIME("text/x-java", {
+ def("text/x-java", {
name: "clike",
keywords: words("abstract assert boolean break byte case catch char class const continue default " +
"do double else enum extends final finally float for goto if implements import " +
@@ -311,7 +312,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
},
modeProps: {fold: ["brace", "import"]}
});
- CodeMirror.defineMIME("text/x-csharp", {
+ def("text/x-csharp", {
name: "clike",
keywords: words("abstract as base break case catch checked class const continue" +
" default delegate do else enum event explicit extern finally fixed for" +
@@ -337,7 +338,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
}
}
});
- CodeMirror.defineMIME("text/x-scala", {
+ def("text/x-scala", {
name: "clike",
keywords: words(
diff --git a/mode/php/php.js b/mode/php/php.js
index 7156dbba6f..bcec3ebb22 100644
--- a/mode/php/php.js
+++ b/mode/php/php.js
@@ -20,17 +20,24 @@
return "string";
};
}
+
+ var phpKeywords = "abstract and array as break case catch class clone const continue declare default " +
+ "do else elseif enddeclare endfor endforeach endif endswitch endwhile extends final " +
+ "for foreach function global goto if implements interface instanceof namespace " +
+ "new or private protected public static switch throw trait try use var while xor " +
+ "die echo empty exit eval include include_once isset list require require_once return " +
+ "print unset __halt_compiler self static parent yield insteadof finally";
+ var phpAtoms = "true false null TRUE FALSE NULL __CLASS__ __DIR__ __FILE__ __LINE__ __METHOD__ __FUNCTION__ __NAMESPACE__ __TRAIT__";
+ var phpBuiltin = "func_num_args func_get_arg func_get_args strlen strcmp strncmp strcasecmp strncasecmp each error_reporting define defined trigger_error user_error set_error_handler restore_error_handler get_declared_classes get_loaded_extensions extension_loaded get_extension_funcs debug_backtrace constant bin2hex hex2bin sleep usleep time mktime gmmktime strftime gmstrftime strtotime date gmdate getdate localtime checkdate flush wordwrap htmlspecialchars htmlentities html_entity_decode md5 md5_file crc32 getimagesize image_type_to_mime_type phpinfo phpversion phpcredits strnatcmp strnatcasecmp substr_count strspn strcspn strtok strtoupper strtolower strpos strrpos strrev hebrev hebrevc nl2br basename dirname pathinfo stripslashes stripcslashes strstr stristr strrchr str_shuffle str_word_count strcoll substr substr_replace quotemeta ucfirst ucwords strtr addslashes addcslashes rtrim str_replace str_repeat count_chars chunk_split trim ltrim strip_tags similar_text explode implode setlocale localeconv parse_str str_pad chop strchr sprintf printf vprintf vsprintf sscanf fscanf parse_url urlencode urldecode rawurlencode rawurldecode readlink linkinfo link unlink exec system escapeshellcmd escapeshellarg passthru shell_exec proc_open proc_close rand srand getrandmax mt_rand mt_srand mt_getrandmax base64_decode base64_encode abs ceil floor round is_finite is_nan is_infinite bindec hexdec octdec decbin decoct dechex base_convert number_format fmod ip2long long2ip getenv putenv getopt microtime gettimeofday getrusage uniqid quoted_printable_decode set_time_limit get_cfg_var magic_quotes_runtime set_magic_quotes_runtime get_magic_quotes_gpc get_magic_quotes_runtime import_request_variables error_log serialize unserialize memory_get_usage var_dump var_export debug_zval_dump print_r highlight_file show_source highlight_string ini_get ini_get_all ini_set ini_alter ini_restore get_include_path set_include_path restore_include_path setcookie header headers_sent connection_aborted connection_status ignore_user_abort parse_ini_file is_uploaded_file move_uploaded_file intval floatval doubleval strval gettype settype is_null is_resource is_bool is_long is_float is_int is_integer is_double is_real is_numeric is_string is_array is_object is_scalar ereg ereg_replace eregi eregi_replace split spliti join sql_regcase dl pclose popen readfile rewind rmdir umask fclose feof fgetc fgets fgetss fread fopen fpassthru ftruncate fstat fseek ftell fflush fwrite fputs mkdir rename copy tempnam tmpfile file file_get_contents stream_select stream_context_create stream_context_set_params stream_context_set_option stream_context_get_options stream_filter_prepend stream_filter_append fgetcsv flock get_meta_tags stream_set_write_buffer set_file_buffer set_socket_blocking stream_set_blocking socket_set_blocking stream_get_meta_data stream_register_wrapper stream_wrapper_register stream_set_timeout socket_set_timeout socket_get_status realpath fnmatch fsockopen pfsockopen pack unpack get_browser crypt opendir closedir chdir getcwd rewinddir readdir dir glob fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype file_exists is_writable is_writeable is_readable is_executable is_file is_dir is_link stat lstat chown touch clearstatcache mail ob_start ob_flush ob_clean ob_end_flush ob_end_clean ob_get_flush ob_get_clean ob_get_length ob_get_level ob_get_status ob_get_contents ob_implicit_flush ob_list_handlers ksort krsort natsort natcasesort asort arsort sort rsort usort uasort uksort shuffle array_walk count end prev next reset current key min max in_array array_search extract compact array_fill range array_multisort array_push array_pop array_shift array_unshift array_splice array_slice array_merge array_merge_recursive array_keys array_values array_count_values array_reverse array_reduce array_pad array_flip array_change_key_case array_rand array_unique array_intersect array_intersect_assoc array_diff array_diff_assoc array_sum array_filter array_map array_chunk array_key_exists pos sizeof key_exists assert assert_options version_compare ftok str_rot13 aggregate session_name session_module_name session_save_path session_id session_regenerate_id session_decode session_register session_unregister session_is_registered session_encode session_start session_destroy session_unset session_set_save_handler session_cache_limiter session_cache_expire session_set_cookie_params session_get_cookie_params session_write_close preg_match preg_match_all preg_replace preg_replace_callback preg_split preg_quote preg_grep overload ctype_alnum ctype_alpha ctype_cntrl ctype_digit ctype_lower ctype_graph ctype_print ctype_punct ctype_space ctype_upper ctype_xdigit virtual apache_request_headers apache_note apache_lookup_uri apache_child_terminate apache_setenv apache_response_headers apache_get_version getallheaders mysql_connect mysql_pconnect mysql_close mysql_select_db mysql_create_db mysql_drop_db mysql_query mysql_unbuffered_query mysql_db_query mysql_list_dbs mysql_list_tables mysql_list_fields mysql_list_processes mysql_error mysql_errno mysql_affected_rows mysql_insert_id mysql_result mysql_num_rows mysql_num_fields mysql_fetch_row mysql_fetch_array mysql_fetch_assoc mysql_fetch_object mysql_data_seek mysql_fetch_lengths mysql_fetch_field mysql_field_seek mysql_free_result mysql_field_name mysql_field_table mysql_field_len mysql_field_type mysql_field_flags mysql_escape_string mysql_real_escape_string mysql_stat mysql_thread_id mysql_client_encoding mysql_get_client_info mysql_get_host_info mysql_get_proto_info mysql_get_server_info mysql_info mysql mysql_fieldname mysql_fieldtable mysql_fieldlen mysql_fieldtype mysql_fieldflags mysql_selectdb mysql_createdb mysql_dropdb mysql_freeresult mysql_numfields mysql_numrows mysql_listdbs mysql_listtables mysql_listfields mysql_db_name mysql_dbname mysql_tablename mysql_table_name pg_connect pg_pconnect pg_close pg_connection_status pg_connection_busy pg_connection_reset pg_host pg_dbname pg_port pg_tty pg_options pg_ping pg_query pg_send_query pg_cancel_query pg_fetch_result pg_fetch_row pg_fetch_assoc pg_fetch_array pg_fetch_object pg_fetch_all pg_affected_rows pg_get_result pg_result_seek pg_result_status pg_free_result pg_last_oid pg_num_rows pg_num_fields pg_field_name pg_field_num pg_field_size pg_field_type pg_field_prtlen pg_field_is_null pg_get_notify pg_get_pid pg_result_error pg_last_error pg_last_notice pg_put_line pg_end_copy pg_copy_to pg_copy_from pg_trace pg_untrace pg_lo_create pg_lo_unlink pg_lo_open pg_lo_close pg_lo_read pg_lo_write pg_lo_read_all pg_lo_import pg_lo_export pg_lo_seek pg_lo_tell pg_escape_string pg_escape_bytea pg_unescape_bytea pg_client_encoding pg_set_client_encoding pg_meta_data pg_convert pg_insert pg_update pg_delete pg_select pg_exec pg_getlastoid pg_cmdtuples pg_errormessage pg_numrows pg_numfields pg_fieldname pg_fieldsize pg_fieldtype pg_fieldnum pg_fieldprtlen pg_fieldisnull pg_freeresult pg_result pg_loreadall pg_locreate pg_lounlink pg_loopen pg_loclose pg_loread pg_lowrite pg_loimport pg_loexport http_response_code get_declared_traits getimagesizefromstring socket_import_stream stream_set_chunk_size trait_exists header_register_callback class_uses session_status session_register_shutdown echo print global static exit array empty eval isset unset die include require include_once require_once";
+ CodeMirror.registerHelper("hintWords", "php", [phpKeywords, phpAtoms, phpBuiltin].join(" ").split(" "));
+
var phpConfig = {
name: "clike",
- keywords: keywords("abstract and array as break case catch class clone const continue declare default " +
- "do else elseif enddeclare endfor endforeach endif endswitch endwhile extends final " +
- "for foreach function global goto if implements interface instanceof namespace " +
- "new or private protected public static switch throw trait try use var while xor " +
- "die echo empty exit eval include include_once isset list require require_once return " +
- "print unset __halt_compiler self static parent yield insteadof finally"),
+ helperType: "php",
+ keywords: keywords(phpKeywords),
blockKeywords: keywords("catch do else elseif for foreach if switch try while finally"),
- atoms: keywords("true false null TRUE FALSE NULL __CLASS__ __DIR__ __FILE__ __LINE__ __METHOD__ __FUNCTION__ __NAMESPACE__ __TRAIT__"),
- builtin: keywords("func_num_args func_get_arg func_get_args strlen strcmp strncmp strcasecmp strncasecmp each error_reporting define defined trigger_error user_error set_error_handler restore_error_handler get_declared_classes get_loaded_extensions extension_loaded get_extension_funcs debug_backtrace constant bin2hex hex2bin sleep usleep time mktime gmmktime strftime gmstrftime strtotime date gmdate getdate localtime checkdate flush wordwrap htmlspecialchars htmlentities html_entity_decode md5 md5_file crc32 getimagesize image_type_to_mime_type phpinfo phpversion phpcredits strnatcmp strnatcasecmp substr_count strspn strcspn strtok strtoupper strtolower strpos strrpos strrev hebrev hebrevc nl2br basename dirname pathinfo stripslashes stripcslashes strstr stristr strrchr str_shuffle str_word_count strcoll substr substr_replace quotemeta ucfirst ucwords strtr addslashes addcslashes rtrim str_replace str_repeat count_chars chunk_split trim ltrim strip_tags similar_text explode implode setlocale localeconv parse_str str_pad chop strchr sprintf printf vprintf vsprintf sscanf fscanf parse_url urlencode urldecode rawurlencode rawurldecode readlink linkinfo link unlink exec system escapeshellcmd escapeshellarg passthru shell_exec proc_open proc_close rand srand getrandmax mt_rand mt_srand mt_getrandmax base64_decode base64_encode abs ceil floor round is_finite is_nan is_infinite bindec hexdec octdec decbin decoct dechex base_convert number_format fmod ip2long long2ip getenv putenv getopt microtime gettimeofday getrusage uniqid quoted_printable_decode set_time_limit get_cfg_var magic_quotes_runtime set_magic_quotes_runtime get_magic_quotes_gpc get_magic_quotes_runtime import_request_variables error_log serialize unserialize memory_get_usage var_dump var_export debug_zval_dump print_r highlight_file show_source highlight_string ini_get ini_get_all ini_set ini_alter ini_restore get_include_path set_include_path restore_include_path setcookie header headers_sent connection_aborted connection_status ignore_user_abort parse_ini_file is_uploaded_file move_uploaded_file intval floatval doubleval strval gettype settype is_null is_resource is_bool is_long is_float is_int is_integer is_double is_real is_numeric is_string is_array is_object is_scalar ereg ereg_replace eregi eregi_replace split spliti join sql_regcase dl pclose popen readfile rewind rmdir umask fclose feof fgetc fgets fgetss fread fopen fpassthru ftruncate fstat fseek ftell fflush fwrite fputs mkdir rename copy tempnam tmpfile file file_get_contents stream_select stream_context_create stream_context_set_params stream_context_set_option stream_context_get_options stream_filter_prepend stream_filter_append fgetcsv flock get_meta_tags stream_set_write_buffer set_file_buffer set_socket_blocking stream_set_blocking socket_set_blocking stream_get_meta_data stream_register_wrapper stream_wrapper_register stream_set_timeout socket_set_timeout socket_get_status realpath fnmatch fsockopen pfsockopen pack unpack get_browser crypt opendir closedir chdir getcwd rewinddir readdir dir glob fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype file_exists is_writable is_writeable is_readable is_executable is_file is_dir is_link stat lstat chown touch clearstatcache mail ob_start ob_flush ob_clean ob_end_flush ob_end_clean ob_get_flush ob_get_clean ob_get_length ob_get_level ob_get_status ob_get_contents ob_implicit_flush ob_list_handlers ksort krsort natsort natcasesort asort arsort sort rsort usort uasort uksort shuffle array_walk count end prev next reset current key min max in_array array_search extract compact array_fill range array_multisort array_push array_pop array_shift array_unshift array_splice array_slice array_merge array_merge_recursive array_keys array_values array_count_values array_reverse array_reduce array_pad array_flip array_change_key_case array_rand array_unique array_intersect array_intersect_assoc array_diff array_diff_assoc array_sum array_filter array_map array_chunk array_key_exists pos sizeof key_exists assert assert_options version_compare ftok str_rot13 aggregate session_name session_module_name session_save_path session_id session_regenerate_id session_decode session_register session_unregister session_is_registered session_encode session_start session_destroy session_unset session_set_save_handler session_cache_limiter session_cache_expire session_set_cookie_params session_get_cookie_params session_write_close preg_match preg_match_all preg_replace preg_replace_callback preg_split preg_quote preg_grep overload ctype_alnum ctype_alpha ctype_cntrl ctype_digit ctype_lower ctype_graph ctype_print ctype_punct ctype_space ctype_upper ctype_xdigit virtual apache_request_headers apache_note apache_lookup_uri apache_child_terminate apache_setenv apache_response_headers apache_get_version getallheaders mysql_connect mysql_pconnect mysql_close mysql_select_db mysql_create_db mysql_drop_db mysql_query mysql_unbuffered_query mysql_db_query mysql_list_dbs mysql_list_tables mysql_list_fields mysql_list_processes mysql_error mysql_errno mysql_affected_rows mysql_insert_id mysql_result mysql_num_rows mysql_num_fields mysql_fetch_row mysql_fetch_array mysql_fetch_assoc mysql_fetch_object mysql_data_seek mysql_fetch_lengths mysql_fetch_field mysql_field_seek mysql_free_result mysql_field_name mysql_field_table mysql_field_len mysql_field_type mysql_field_flags mysql_escape_string mysql_real_escape_string mysql_stat mysql_thread_id mysql_client_encoding mysql_get_client_info mysql_get_host_info mysql_get_proto_info mysql_get_server_info mysql_info mysql mysql_fieldname mysql_fieldtable mysql_fieldlen mysql_fieldtype mysql_fieldflags mysql_selectdb mysql_createdb mysql_dropdb mysql_freeresult mysql_numfields mysql_numrows mysql_listdbs mysql_listtables mysql_listfields mysql_db_name mysql_dbname mysql_tablename mysql_table_name pg_connect pg_pconnect pg_close pg_connection_status pg_connection_busy pg_connection_reset pg_host pg_dbname pg_port pg_tty pg_options pg_ping pg_query pg_send_query pg_cancel_query pg_fetch_result pg_fetch_row pg_fetch_assoc pg_fetch_array pg_fetch_object pg_fetch_all pg_affected_rows pg_get_result pg_result_seek pg_result_status pg_free_result pg_last_oid pg_num_rows pg_num_fields pg_field_name pg_field_num pg_field_size pg_field_type pg_field_prtlen pg_field_is_null pg_get_notify pg_get_pid pg_result_error pg_last_error pg_last_notice pg_put_line pg_end_copy pg_copy_to pg_copy_from pg_trace pg_untrace pg_lo_create pg_lo_unlink pg_lo_open pg_lo_close pg_lo_read pg_lo_write pg_lo_read_all pg_lo_import pg_lo_export pg_lo_seek pg_lo_tell pg_escape_string pg_escape_bytea pg_unescape_bytea pg_client_encoding pg_set_client_encoding pg_meta_data pg_convert pg_insert pg_update pg_delete pg_select pg_exec pg_getlastoid pg_cmdtuples pg_errormessage pg_numrows pg_numfields pg_fieldname pg_fieldsize pg_fieldtype pg_fieldnum pg_fieldprtlen pg_fieldisnull pg_freeresult pg_result pg_loreadall pg_locreate pg_lounlink pg_loopen pg_loclose pg_loread pg_lowrite pg_loimport pg_loexport http_response_code get_declared_traits getimagesizefromstring socket_import_stream stream_set_chunk_size trait_exists header_register_callback class_uses session_status session_register_shutdown echo print global static exit array empty eval isset unset die include require include_once require_once"),
+ atoms: keywords(phpAtoms),
+ builtin: keywords(phpBuiltin),
multiLineStrings: true,
hooks: {
"$": function(stream) {
From 908342c7504f9ff440d7e5bec51399f776a6fec4 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Tue, 8 Apr 2014 11:04:36 +0200
Subject: [PATCH 095/127] [matchbrackets addon] Fix highlighting of brackets
when scan reaches end/start of doc
Issue #2442
---
addon/edit/matchbrackets.js | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/addon/edit/matchbrackets.js b/addon/edit/matchbrackets.js
index b889fa3ae5..dcdde81dfe 100644
--- a/addon/edit/matchbrackets.js
+++ b/addon/edit/matchbrackets.js
@@ -22,6 +22,7 @@
var style = cm.getTokenTypeAt(Pos(where.line, pos + 1));
var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config);
+ if (found == null) return null;
return {from: Pos(where.line, pos), to: found && found.pos,
match: found && found.ch == match.charAt(0), forward: dir > 0};
}
@@ -30,9 +31,12 @@
// should be a regexp, e.g. /[[\]]/
//
// Note: If "where" is on an open bracket, then this bracket is ignored.
+ //
+ // Returns false when no bracket was found, null when it reached
+ // maxScanLines and gave up
function scanForBracket(cm, where, dir, style, config) {
var maxScanLen = (config && config.maxScanLineLength) || 10000;
- var maxScanLines = (config && config.maxScanLines) || 500;
+ var maxScanLines = (config && config.maxScanLines) || 1000;
var stack = [];
var re = config && config.bracketRegex ? config.bracketRegex : /[(){}[\]]/;
@@ -54,6 +58,7 @@
}
}
}
+ return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null;
}
function matchBrackets(cm, autoclear, config) {
@@ -62,11 +67,10 @@
var marks = [], ranges = cm.listSelections();
for (var i = 0; i < ranges.length; i++) {
var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, false, config);
- if (match && cm.getLine(match.from.line).length <= maxHighlightLen &&
- match.to && cm.getLine(match.to.line).length <= maxHighlightLen) {
+ if (match && cm.getLine(match.from.line).length <= maxHighlightLen) {
var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style}));
- if (match.to)
+ if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen)
marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style}));
}
}
From e9cd523ea1340ce73d6642a6703ea810c498c5f8 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Tue, 8 Apr 2014 14:49:19 +0200
Subject: [PATCH 096/127] Fix addLineClass (and similar) returning null on
no-op
When the call didn't result in an actual change (for example
line already had the given class), changeLine would return null.
This doesn't seem useful, and caused issue #2438. It now always
returns the line handle (as documented).
---
lib/codemirror.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/lib/codemirror.js b/lib/codemirror.js
index a37c921391..1a70cd68de 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -3674,7 +3674,6 @@
else no = lineNo(handle);
if (no == null) return null;
if (op(line, no)) regLineChange(cm, no, changeType);
- else return null;
return line;
}
From 981a01f3e0857e6f98cbbe4b753471729c42017e Mon Sep 17 00:00:00 2001
From: as3boyan
Date: Wed, 9 Apr 2014 10:17:53 +0300
Subject: [PATCH 097/127] [haxe mode] Add HXML mode
---
mode/haxe/haxe.js | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++
mode/haxe/index.html | 29 ++++++++++++++++++----
2 files changed, 93 insertions(+), 4 deletions(-)
diff --git a/mode/haxe/haxe.js b/mode/haxe/haxe.js
index 83224d86e4..e4d7347219 100644
--- a/mode/haxe/haxe.js
+++ b/mode/haxe/haxe.js
@@ -443,4 +443,72 @@ CodeMirror.defineMode("haxe", function(config, parserConfig) {
CodeMirror.defineMIME("text/x-haxe", "haxe");
+CodeMirror.defineMode("hxml", function () {
+
+ return {
+ startState: function () {
+ return {
+ define: false,
+ inString: false
+ };
+ },
+ token: function (stream, state) {
+ var ch = stream.peek();
+ var sol = stream.sol();
+
+ ///* comments */
+ if (ch == "#") {
+ stream.skipToEnd();
+ return "comment";
+ }
+ if (sol && ch == "-") {
+ var style = "variable-2";
+
+ stream.eat(/-/);
+
+ if (stream.peek() == "-") {
+ stream.eat(/-/);
+ style = "keyword a";
+ }
+
+ if (stream.peek() == "D") {
+ stream.eat(/[D]/);
+ style = "keyword c";
+ state.define = true;
+ }
+
+ stream.eatWhile(/[A-Z]/i);
+ return style;
+ }
+
+ var ch = stream.peek();
+
+ if (state.inString == false && ch == "'") {
+ state.inString = true;
+ ch = stream.next();
+ }
+
+ if (state.inString == true) {
+ if (stream.skipTo("'")) {
+
+ } else {
+ stream.skipToEnd();
+ }
+
+ if (stream.peek() == "'") {
+ stream.next();
+ state.inString = false;
+ }
+
+ return "string";
+ }
+
+ stream.next();
+ return null;
+ }
+ };
+});
+
+CodeMirror.defineMIME("text/x-hxml", "hxml");
+
});
diff --git a/mode/haxe/index.html b/mode/haxe/index.html
index ec3b8e0e75..4c3b9783bb 100644
--- a/mode/haxe/index.html
+++ b/mode/haxe/index.html
@@ -26,7 +26,7 @@
Haxe mode
-
+
import one.two.Three;
@attr("test")
@@ -89,15 +89,36 @@
grey( v : Int );
rgb (r:Int,g:Int,b:Int);
}
-
+
+
+
Hxml mode:
+
+
+-cp test
+-js path/to/file.js
+#-remap nme:flash
+--next
+-D source-map-content
+-cmd 'test'
+-lib lime
+
+
- MIME types defined: text/x-haxe.
+ MIME types defined: text/x-haxe, text/x-hxml.
From 08b4d1e27f67fe1d86d2be526a646e82909b295c Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Wed, 9 Apr 2014 15:53:29 +0200
Subject: [PATCH 098/127] [runmode addon] Call blankLine when available
---
addon/runmode/runmode-standalone.js | 1 +
addon/runmode/runmode.js | 1 +
addon/runmode/runmode.node.js | 1 +
3 files changed, 3 insertions(+)
diff --git a/addon/runmode/runmode-standalone.js b/addon/runmode/runmode-standalone.js
index eaa2b8f2fb..aba6f0e139 100644
--- a/addon/runmode/runmode-standalone.js
+++ b/addon/runmode/runmode-standalone.js
@@ -139,6 +139,7 @@ CodeMirror.runMode = function (string, modespec, callback, options) {
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();
while (!stream.eol()) {
var style = mode.token(stream, state);
callback(stream.current(), style, i, stream.start, state);
diff --git a/addon/runmode/runmode.js b/addon/runmode/runmode.js
index 351840e08e..44c17b1a48 100644
--- a/addon/runmode/runmode.js
+++ b/addon/runmode/runmode.js
@@ -57,6 +57,7 @@ CodeMirror.runMode = function(string, modespec, callback, options) {
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();
while (!stream.eol()) {
var style = mode.token(stream, state);
callback(stream.current(), style, i, stream.start, state);
diff --git a/addon/runmode/runmode.node.js b/addon/runmode/runmode.node.js
index 74c39be7e7..54be6e930a 100644
--- a/addon/runmode/runmode.node.js
+++ b/addon/runmode/runmode.node.js
@@ -107,6 +107,7 @@ exports.runMode = function(string, modespec, callback, options) {
for (var i = 0, e = lines.length; i < e; ++i) {
if (i) callback("\n");
var stream = new exports.StringStream(lines[i]);
+ if (!stream.string && mode.blankLine) mode.blankLine();
while (!stream.eol()) {
var style = mode.token(stream, state);
callback(stream.current(), style, i, stream.start, state);
From 8a6778baf496da5c80fe785304fdd0e3d5ec8adb Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Wed, 9 Apr 2014 22:26:50 +0200
Subject: [PATCH 099/127] Revert "Remove fakedLastChar hack"
This reverts commit 475b2be0da668724fa910dc70579820eb3ad905e.
Issue #2452
Issue #2384
---
lib/codemirror.js | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/lib/codemirror.js b/lib/codemirror.js
index 1a70cd68de..911d0aa21c 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -2225,6 +2225,11 @@
// will be the case when there is a lot of text in the textarea,
// in which case reading its value would be expensive.
if (!cm.state.focused || hasSelection(input) || isReadOnly(cm) || cm.options.disableInput) return false;
+ // See paste handler for more on the fakedLastChar kludge
+ if (cm.state.pasteIncoming && cm.state.fakedLastChar) {
+ input.value = input.value.substring(0, input.value.length - 1);
+ cm.state.fakedLastChar = false;
+ }
var text = input.value;
// If nothing changed, bail.
if (text == prevInput && !cm.somethingSelected()) return false;
@@ -2424,6 +2429,16 @@
fastPoll(cm);
});
on(d.input, "paste", function() {
+ // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206
+ // Add a char to the end of textarea before paste occur so that
+ // selection doesn't span to the end of textarea.
+ if (webkit && !cm.state.fakedLastChar && !(new Date - cm.state.lastMiddleDown < 200)) {
+ var start = d.input.selectionStart, end = d.input.selectionEnd;
+ d.input.value += "$";
+ d.input.selectionStart = start;
+ d.input.selectionEnd = end;
+ cm.state.fakedLastChar = true;
+ }
cm.state.pasteIncoming = true;
fastPoll(cm);
});
From 17eb93d8cce970ebc62a4a7589a5204b6aa74dc4 Mon Sep 17 00:00:00 2001
From: mtaran-google
Date: Thu, 10 Apr 2014 15:40:38 -0700
Subject: [PATCH 100/127] [go mode] Set Go mode to use brace folding
---
mode/go/go.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/mode/go/go.js b/mode/go/go.js
index 7ba780ead8..82463052f6 100644
--- a/mode/go/go.js
+++ b/mode/go/go.js
@@ -169,6 +169,7 @@ CodeMirror.defineMode("go", function(config) {
},
electricChars: "{}):",
+ fold: "brace",
blockCommentStart: "/*",
blockCommentEnd: "*/",
lineComment: "//"
From 2d8719ac5732f7d66d58d8c95bdf028dc2cc8f4c Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Wed, 16 Apr 2014 11:24:47 +0200
Subject: [PATCH 101/127] Prevent overlay token types from showing up in
getTokenTypeAt output
Issue #2457
---
lib/codemirror.js | 13 ++++++++-----
test/test.js | 13 +++++++++++++
2 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/lib/codemirror.js b/lib/codemirror.js
index 911d0aa21c..50a20b657c 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -3914,13 +3914,16 @@
pos = clipPos(this.doc, pos);
var styles = getLineStyles(this, getLine(this.doc, pos.line));
var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
- if (ch == 0) return styles[2];
- for (;;) {
+ var type;
+ if (ch == 0) type = styles[2];
+ else for (;;) {
var mid = (before + after) >> 1;
if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid;
else if (styles[mid * 2 + 1] < ch) before = mid + 1;
- else return styles[mid * 2 + 2];
+ else { type = styles[mid * 2 + 2]; break; }
}
+ var cut = type ? type.indexOf("cm-overlay ") : -1;
+ return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1);
},
getModeAt: function(pos) {
@@ -5636,12 +5639,12 @@
}
if (!style) return;
if (overlay.opaque) {
- st.splice(start, i - start, end, style);
+ st.splice(start, i - start, end, "cm-overlay " + style);
i = start + 2;
} else {
for (; start < i; start += 2) {
var cur = st[start+1];
- st[start+1] = cur ? cur + " " + style : style;
+ st[start+1] = (cur ? cur + " " : "") + "cm-overlay " + style;
}
}
}, lineClasses);
diff --git a/test/test.js b/test/test.js
index 8c3a307d53..7d597688a8 100644
--- a/test/test.js
+++ b/test/test.js
@@ -1890,3 +1890,16 @@ testCM("alwaysMergeSelEventWithChangeOrigin", function(cm) {
cm.undoSelection();
eq(cm.getValue(), "Va");
}, {value: "a"});
+
+testCM("getTokenTypeAt", function(cm) {
+ eq(cm.getTokenTypeAt(Pos(0, 0)), "number");
+ eq(cm.getTokenTypeAt(Pos(0, 6)), "string");
+ cm.addOverlay({
+ token: function(stream) {
+ if (stream.match("foo")) return "foo";
+ else stream.next();
+ }
+ });
+ eq(byClassName(cm.getWrapperElement(), "cm-foo").length, 1);
+ eq(cm.getTokenTypeAt(Pos(0, 6)), "string");
+}, {value: "1 + 'foo'", mode: "javascript"});
From 6c4d1054e162d8cd862505ed20d161327f81b735 Mon Sep 17 00:00:00 2001
From: Takuji Shimokawa
Date: Sat, 29 Mar 2014 15:57:59 +0900
Subject: [PATCH 102/127] Refines the text selection detection in readInput
function.
This change is for enabling the display update while inputting text via the input method.
---
lib/codemirror.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lib/codemirror.js b/lib/codemirror.js
index 50a20b657c..f655e27b61 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -2224,7 +2224,8 @@
// possible when it is clear that nothing happened. hasSelection
// will be the case when there is a lot of text in the textarea,
// in which case reading its value would be expensive.
- if (!cm.state.focused || hasSelection(input) || isReadOnly(cm) || cm.options.disableInput) return false;
+ if (!cm.state.focused || (hasSelection(input) && !prevInput) || isReadOnly(cm) || cm.options.disableInput)
+ return false;
// See paste handler for more on the fakedLastChar kludge
if (cm.state.pasteIncoming && cm.state.fakedLastChar) {
input.value = input.value.substring(0, input.value.length - 1);
From 9d2eeed774cfcf93393ff56530c4f9d3d1a37e69 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Wed, 16 Apr 2014 12:09:54 +0200
Subject: [PATCH 103/127] Fix context menu select-all in IE11
Issue #2463
---
lib/codemirror.js | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/lib/codemirror.js b/lib/codemirror.js
index f655e27b61..9a47f3aa46 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -3104,7 +3104,10 @@
signal(cm, "focus", cm);
cm.state.focused = true;
addClass(cm.display.wrapper, "CodeMirror-focused");
- if (!cm.curOp) {
+ // The prevInput test prevents this from firing when a context
+ // menu is closed (since the resetInput would kill the
+ // select-all detection hack)
+ if (!cm.curOp && cm.display.prevInput != "\u200b") {
resetInput(cm);
if (webkit) setTimeout(bind(resetInput, cm, true), 0); // Issue #1730
}
@@ -3173,7 +3176,7 @@
if (display.input.selectionStart != null) {
if (!ie || ie_upto8) prepareSelectAllHack();
clearTimeout(detectingSelectAll);
- var i = 0, poll = function(){
+ var i = 0, poll = function() {
if (display.prevInput == "\u200b" && display.input.selectionStart == 0)
operation(cm, commands.selectAll)(cm);
else if (i++ < 10) detectingSelectAll = setTimeout(poll, 500);
From e546c8e4fffe67b918761617291e15ccae23544a Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Wed, 16 Apr 2014 12:34:44 +0200
Subject: [PATCH 104/127] Be more accurate about which handlers to fire change
events for
I.e. don't fire for a handler that wasn't registered when the change happened.
---
lib/codemirror.js | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/lib/codemirror.js b/lib/codemirror.js
index 9a47f3aa46..33b9811599 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -1955,11 +1955,8 @@
delayedCallbacks = null;
}
// Fire change events, and delayed event handlers
- if (op.changeObjs) {
- for (var i = 0; i < op.changeObjs.length; i++)
- signal(cm, "change", cm, op.changeObjs[i]);
+ if (op.changeObjs)
signal(cm, "changes", cm, op.changeObjs);
- }
if (op.cursorActivity) signal(cm, "cursorActivity", cm, op.origin);
if (delayed) for (var i = 0; i < delayed.length; ++i) delayed[i]();
}
@@ -3481,13 +3478,17 @@
else
regChange(cm, from.line, to.line + 1, lendiff);
- if (hasHandler(cm, "change") || hasHandler(cm, "changes"))
- (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push({
+ var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change");
+ if (changeHandler || changesHandler) {
+ var obj = {
from: from, to: to,
text: change.text,
removed: change.removed,
origin: change.origin
- });
+ };
+ if (changeHandler) signalLater(cm, "change", cm, obj);
+ if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj);
+ }
}
function replaceRange(doc, code, from, to, origin) {
From 8b1a5bb7b72e4987893f2402aa36fbf79d09b905 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Wed, 16 Apr 2014 13:06:22 +0200
Subject: [PATCH 105/127] Be more precise about which cursorActivity handlers
to fire
Issue #2464
---
keymap/vim.js | 4 ++--
lib/codemirror.js | 25 +++++++++++++++++--------
2 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/keymap/vim.js b/keymap/vim.js
index 6fedf93292..42e4522693 100644
--- a/keymap/vim.js
+++ b/keymap/vim.js
@@ -4062,7 +4062,7 @@
/**
* Listens for any kind of cursor activity on CodeMirror.
*/
- function onCursorActivity(cm, origin) {
+ function onCursorActivity(cm) {
var vim = cm.state.vim;
if (vim.insertMode) {
// Tracking cursor activity in insert mode (for macro support).
@@ -4075,7 +4075,7 @@
// Cursor moved outside the context of an edit. Reset the change.
lastChange.changes = [];
}
- } else if (origin == '*mouse') {
+ } else if (cm.doc.history.lastSelOrigin == '*mouse') {
// Reset lastHPos if mouse click was done in normal mode.
vim.lastHPos = cm.doc.getCursor().ch;
}
diff --git a/lib/codemirror.js b/lib/codemirror.js
index 33b9811599..cb80d8c7c0 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -1131,7 +1131,6 @@
// Set a new selection.
function setSelection(doc, sel, options) {
- if (options && options.origin && doc.cm) doc.cm.curOp.origin = options.origin;
setSelectionNoUndo(doc, sel, options);
addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);
}
@@ -1152,9 +1151,10 @@
doc.sel = sel;
- if (doc.cm)
- doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged =
- doc.cm.curOp.cursorActivity = true;
+ if (doc.cm) {
+ doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true;
+ signalCursorActivity(doc.cm);
+ }
signalLater(doc, "cursorActivity", doc);
}
@@ -1889,8 +1889,7 @@
updateInput: null, // Whether to reset the input textarea
typing: false, // Whether this reset should be careful to leave existing text (for compositing)
changeObjs: null, // Accumulated changes, for firing change events
- origin: null, // Selection's origin
- cursorActivity: false, // Whether to fire a cursorActivity event
+ cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
selectionChanged: false, // Whether the selection needs to be redrawn
updateMaxLine: false, // Set when the widest line needs to be determined anew
scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
@@ -1957,7 +1956,9 @@
// Fire change events, and delayed event handlers
if (op.changeObjs)
signal(cm, "changes", cm, op.changeObjs);
- if (op.cursorActivity) signal(cm, "cursorActivity", cm, op.origin);
+ if (op.cursorActivityHandlers)
+ for (var i = 0; i < op.cursorActivityHandlers.length; i++)
+ op.cursorActivityHandlers[i](cm);
if (delayed) for (var i = 0; i < delayed.length; ++i) delayed[i]();
}
@@ -3450,7 +3451,7 @@
}
if (doc.sel.contains(change.from, change.to) > -1)
- cm.curOp.cursorActivity = true;
+ signalCursorActivity(cm);
updateDoc(doc, change, spans, estimateHeight(cm));
@@ -6919,6 +6920,14 @@
return e_defaultPrevented(e) || e.codemirrorIgnore;
}
+ function signalCursorActivity(cm) {
+ var arr = cm._handlers && cm._handlers.cursorActivity;
+ if (!arr) return;
+ var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
+ for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1)
+ set.push(arr[i]);
+ }
+
function hasHandler(emitter, type) {
var arr = emitter._handlers && emitter._handlers[type];
return arr && arr.length > 0;
From 357cf2d9652f495d741c129b63ff7892a5caf3ef Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Wed, 16 Apr 2014 13:18:59 +0200
Subject: [PATCH 106/127] [css mode] Fix tokenizing of empty url() token
Issue #2465
---
mode/css/css.js | 2 +-
mode/css/test.js | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/mode/css/css.js b/mode/css/css.js
index 3426732cdc..7a396ee451 100644
--- a/mode/css/css.js
+++ b/mode/css/css.js
@@ -92,7 +92,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
function tokenParenthesized(stream, state) {
stream.next(); // Must be '('
- if (!stream.match(/\s*[\"\']/, false))
+ if (!stream.match(/\s*[\"\')]/, false))
state.tokenize = tokenString(")");
else
state.tokenize = null;
diff --git a/mode/css/test.js b/mode/css/test.js
index b3f47767e6..f9f667295c 100644
--- a/mode/css/test.js
+++ b/mode/css/test.js
@@ -116,4 +116,7 @@
" [property src]: [atom url]([string http://blah]),",
" [atom url]([string http://foo]);",
"}");
+
+ MT("empty_url",
+ "[def @import] [tag url]() [tag screen];");
})();
From 973b776d04ac40fc434731488786cca37dc5e5cc Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Wed, 16 Apr 2014 13:26:11 +0200
Subject: [PATCH 107/127] Guard against NaN when computing horiz padding
Issue #2467
---
lib/codemirror.js | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lib/codemirror.js b/lib/codemirror.js
index cb80d8c7c0..cfac7fab7c 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -1454,8 +1454,9 @@
if (display.cachedPaddingH) return display.cachedPaddingH;
var e = removeChildrenAndAdd(display.measure, elt("pre", "x"));
var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
- return display.cachedPaddingH = {left: parseInt(style.paddingLeft),
- right: parseInt(style.paddingRight)};
+ var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};
+ if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data;
+ return data;
}
// Ensure the lineView.wrapping.heights array is populated. This is
From eed9a2c8c782711fc25c0002d643f016f20061ef Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Wed, 16 Apr 2014 14:21:53 +0200
Subject: [PATCH 108/127] Call cursorActivity handlers after other handlers
To preserve existing change/cursorActivity handler ordering
---
lib/codemirror.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/codemirror.js b/lib/codemirror.js
index cfac7fab7c..bd03fdb36f 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -1957,10 +1957,10 @@
// Fire change events, and delayed event handlers
if (op.changeObjs)
signal(cm, "changes", cm, op.changeObjs);
+ if (delayed) for (var i = 0; i < delayed.length; ++i) delayed[i]();
if (op.cursorActivityHandlers)
for (var i = 0; i < op.cursorActivityHandlers.length; i++)
op.cursorActivityHandlers[i](cm);
- if (delayed) for (var i = 0; i < delayed.length; ++i) delayed[i]();
}
// Run the given function in an operation
From 6f7127d685174d44fbe956193c8a4cdf32c17658 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Wed, 16 Apr 2014 17:02:24 +0200
Subject: [PATCH 109/127] [r mode] Remove license link
All of the distribution is under a single license.
---
mode/r/index.html | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/mode/r/index.html b/mode/r/index.html
index f73e13d621..397d5858a3 100644
--- a/mode/r/index.html
+++ b/mode/r/index.html
@@ -80,7 +80,6 @@
MIME types defined: text/x-rsrc.
Development of the CodeMirror R mode was kindly sponsored
- by Ubalo , who hold
- the license .
+ by Ubalo .
From 306a09020ff570c2a75216da470ed6b1e7c6f452 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Thu, 17 Apr 2014 09:37:21 +0200
Subject: [PATCH 110/127] [javascript mode] Properly parse quasi quotes without
prefix
Closes #2472
---
mode/javascript/javascript.js | 10 ++++++----
mode/javascript/test.js | 3 +++
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js
index 9318aabe99..daf138ba8d 100644
--- a/mode/javascript/javascript.js
+++ b/mode/javascript/javascript.js
@@ -366,6 +366,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
if (type == "{") return contCommasep(objprop, "}", null, maybeop);
+ if (type == "quasi") { return pass(quasi, maybeop); }
return cont();
}
function maybeexpression(type) {
@@ -390,21 +391,22 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (value == "?") return cont(expression, expect(":"), expr);
return cont(expr);
}
- if (type == "quasi") { cx.cc.push(me); return quasi(value); }
+ if (type == "quasi") { return pass(quasi, me); }
if (type == ";") return;
if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
if (type == ".") return cont(property, me);
if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
}
- function quasi(value) {
- if (value.slice(value.length - 2) != "${") return cont();
+ function quasi(type, value) {
+ if (type != "quasi") return pass();
+ if (value.slice(value.length - 2) != "${") return cont(quasi);
return cont(expression, continueQuasi);
}
function continueQuasi(type) {
if (type == "}") {
cx.marked = "string-2";
cx.state.tokenize = tokenQuasi;
- return cont();
+ return cont(quasi);
}
}
function arrowBody(type) {
diff --git a/mode/javascript/test.js b/mode/javascript/test.js
index 36341862f0..782f0457f9 100644
--- a/mode/javascript/test.js
+++ b/mode/javascript/test.js
@@ -70,6 +70,9 @@
MT("quasi",
"[variable re][string-2 `fofdlakj${][variable x] [operator +] ([variable re][string-2 `foo`]) [operator +] [number 1][string-2 }fdsa`] [operator +] [number 2]");
+ MT("quasi_no_function",
+ "[variable x] [operator =] [string-2 `fofdlakj${][variable x] [operator +] [string-2 `foo`] [operator +] [number 1][string-2 }fdsa`] [operator +] [number 2]");
+
MT("indent_statement",
"[keyword var] [variable x] [operator =] [number 10]",
"[variable x] [operator +=] [variable y] [operator +]",
From 5c6366faaeca35662fff50af3e943b0b91a419e0 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Thu, 17 Apr 2014 15:39:58 +0200
Subject: [PATCH 111/127] [xml mode] Fix giant indentation when continuing an
attribute on a long line
Closes #2473
---
mode/xml/xml.js | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/mode/xml/xml.js b/mode/xml/xml.js
index b8c4297976..3248c454d1 100644
--- a/mode/xml/xml.js
+++ b/mode/xml/xml.js
@@ -321,7 +321,10 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
var context = state.context;
// Indent multi-line strings (e.g. css).
if (state.tokenize.isInAttribute) {
- return state.stringStartCol + 1;
+ if (state.tagStart == state.indented)
+ return state.stringStartCol + 1;
+ else
+ return state.indented + indentUnit;
}
if (context && context.noIndent) return CodeMirror.Pass;
if (state.tokenize != inTag && state.tokenize != inText)
From beb975f7e76c734044fa35a2c9a64b97f9eb5c94 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Radek=20Pi=C3=B3rkowski?=
Date: Tue, 15 Apr 2014 21:13:31 +0200
Subject: [PATCH 112/127] [php mode] Add support for interpolated variables in
double-quoted strings.
---
mode/php/index.html | 6 ++-
mode/php/php.js | 97 ++++++++++++++++++++++++++++++++++-
mode/php/test.js | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++
test/index.html | 3 ++
4 files changed, 249 insertions(+), 2 deletions(-)
create mode 100644 mode/php/test.js
diff --git a/mode/php/index.html b/mode/php/index.html
index 1fb7435bb1..dd25a5e788 100644
--- a/mode/php/index.html
+++ b/mode/php/index.html
@@ -32,8 +32,12 @@
PHP mode
1, 'b' => 2, 3 => 'c');
+
+echo "$a[a] ${a[3] /* } comment */} {$a[b]} \$a[a]";
+
function hello($who) {
- return "Hello " . $who;
+ return "Hello $who!";
}
?>
The program says = hello("World") ?>.
diff --git a/mode/php/php.js b/mode/php/php.js
index bcec3ebb22..184293b62b 100644
--- a/mode/php/php.js
+++ b/mode/php/php.js
@@ -21,6 +21,82 @@
};
}
+ // Two helper functions for encapsList
+ function matchFirst(list) {
+ return function (stream) {
+ for (var i = 0; i < list.length; ++i)
+ if (stream.match(list[i][0]))
+ return list[i][1];
+ return false;
+ };
+ }
+ function matchSequence(list) {
+ if (list.length == 0) return encapsList;
+ return function (stream, state) {
+ var result = list[0](stream, state);
+ if (result !== false) {
+ state.tokenize = matchSequence(list.slice(1));
+ return result;
+ }
+ else {
+ state.tokenize = encapsList;
+ return "string";
+ }
+ };
+ }
+ function encapsList(stream, state) {
+ var escaped = false, next, end = false;
+
+ if (stream.current() == '"') return "string";
+
+ // "Complex" syntax
+ if (stream.match("${", false) || stream.match("{$", false)) {
+ state.tokenize = null;
+ return "string";
+ }
+
+ // Simple syntax
+ if (stream.match(/\$[a-zA-Z_][a-zA-Z0-9_]*/)) {
+ // After the variable name there may appear array or object operator.
+ if (stream.match("[", false)) {
+ // Match array operator
+ state.tokenize = matchSequence([
+ matchFirst([["[", null]]),
+ matchFirst([
+ [/\d[\w\.]*/, "number"],
+ [/\$[a-zA-Z_][a-zA-Z0-9_]*/, "variable-2"],
+ [/[\w\$]+/, "variable"]
+ ]),
+ matchFirst([["]", null]])
+ ]);
+ }
+ if (stream.match(/\-\>\w/, false)) {
+ // Match object operator
+ state.tokenize = matchSequence([
+ matchFirst([["->", null]]),
+ matchFirst([[/[\w]+/, "variable"]])
+ ]);
+ }
+ return "variable-2";
+ }
+
+ // Normal string
+ while (
+ !stream.eol() &&
+ (!stream.match("{$", false)) &&
+ (!stream.match(/(\$[a-zA-Z_][a-zA-Z0-9_]*|\$\{)/, false) || escaped)
+ ) {
+ next = stream.next();
+ if (!escaped && next == '"') { end = true; break; }
+ escaped = !escaped && next == "\\";
+ }
+ if (end) {
+ state.tokenize = null;
+ state.phpEncapsStack.pop();
+ }
+ return "string";
+ }
+
var phpKeywords = "abstract and array as break case catch class clone const continue declare default " +
"do else elseif enddeclare endfor endforeach endif endswitch endwhile extends final " +
"for foreach function global goto if implements interface instanceof namespace " +
@@ -62,6 +138,24 @@
return "comment";
}
return false;
+ },
+ '"': function(stream, state) {
+ if (!state.phpEncapsStack)
+ state.phpEncapsStack = [];
+ state.phpEncapsStack.push(0);
+ state.tokenize = encapsList;
+ return state.tokenize(stream, state);
+ },
+ "{": function(_stream, state) {
+ if (state.phpEncapsStack && state.phpEncapsStack.length > 0)
+ state.phpEncapsStack[state.phpEncapsStack.length - 1]++;
+ return false;
+ },
+ "}": function(_stream, state) {
+ if (state.phpEncapsStack && state.phpEncapsStack.length > 0)
+ if (--state.phpEncapsStack[state.phpEncapsStack.length - 1] == 0)
+ state.tokenize = encapsList;
+ return false;
}
}
};
@@ -101,7 +195,8 @@
state.curState = state.html;
return "meta";
} else {
- return phpMode.token(stream, state.curState);
+ var result = phpMode.token(stream, state.curState);
+ return (stream.pos <= stream.start) ? phpMode.token(stream, state.curState) : result;
}
}
diff --git a/mode/php/test.js b/mode/php/test.js
new file mode 100644
index 0000000000..db68d75de3
--- /dev/null
+++ b/mode/php/test.js
@@ -0,0 +1,145 @@
+(function() {
+ var mode = CodeMirror.getMode({indentUnit: 2}, "php");
+ function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
+
+ MT('simple_test',
+ '[meta ]');
+
+ MT('variable_interpolation_non_alphanumeric',
+ '[meta $/$\\$}$\\\"$:$;$?$|$[[$]]$+$=aaa"]',
+ '[meta ?>]');
+
+ MT('variable_interpolation_digits',
+ '[meta ]');
+
+ MT('variable_interpolation_simple_syntax_1',
+ '[meta ]');
+
+ MT('variable_interpolation_simple_syntax_2',
+ '[meta ]');
+
+ MT('variable_interpolation_simple_syntax_3',
+ '[meta [variable aaaaa][string .aaaaaa"];',
+ '[keyword echo] [string "aaa][variable-2 $aaaa][string ->][variable-2 $aaaaa][string .aaaaaa"];',
+ '[keyword echo] [string "aaa][variable-2 $aaaa]->[variable aaaaa][string [[2]].aaaaaa"];',
+ '[keyword echo] [string "aaa][variable-2 $aaaa]->[variable aaaaa][string ->aaaa2.aaaaaa"];',
+ '[meta ?>]');
+
+ MT('variable_interpolation_escaping',
+ '[meta aaa.aaa"];',
+ '[keyword echo] [string "aaa\\$aaaa[[2]]aaa.aaa"];',
+ '[keyword echo] [string "aaa\\$aaaa[[asd]]aaa.aaa"];',
+ '[keyword echo] [string "aaa{\\$aaaa->aaa.aaa"];',
+ '[keyword echo] [string "aaa{\\$aaaa[[2]]aaa.aaa"];',
+ '[keyword echo] [string "aaa{\\aaaaa[[asd]]aaa.aaa"];',
+ '[keyword echo] [string "aaa\\${aaaa->aaa.aaa"];',
+ '[keyword echo] [string "aaa\\${aaaa[[2]]aaa.aaa"];',
+ '[keyword echo] [string "aaa\\${aaaa[[asd]]aaa.aaa"];',
+ '[meta ?>]');
+
+ MT('variable_interpolation_complex_syntax_1',
+ '[meta aaa.aaa"];',
+ '[keyword echo] [string "aaa][variable-2 $]{[variable-2 $aaaa]}[string ->aaa.aaa"];',
+ '[keyword echo] [string "aaa][variable-2 $]{[variable-2 $aaaa][[',' [number 42]',']]}[string ->aaa.aaa"];',
+ '[keyword echo] [string "aaa][variable-2 $]{[variable aaaa][meta ?>]aaaaaa');
+
+ MT('variable_interpolation_complex_syntax_2',
+ '[meta } $aaaaaa.aaa"];',
+ '[keyword echo] [string "][variable-2 $]{[variable aaa][comment /*}?>*/][[',' [string "aaa][variable-2 $aaa][string {}][variable-2 $]{[variable aaa]}[string "]',']]}[string ->aaa.aaa"];',
+ '[keyword echo] [string "][variable-2 $]{[variable aaa][comment /*} } $aaa } */]}[string ->aaa.aaa"];');
+
+
+ function build_recursive_monsters(nt, t, n){
+ var monsters = [t];
+ for (var i = 1; i <= n; ++i)
+ monsters[i] = nt.join(monsters[i - 1]);
+ return monsters;
+ }
+
+ var m1 = build_recursive_monsters(
+ ['[string "][variable-2 $]{[variable aaa] [operator +] ', '}[string "]'],
+ '[comment /* }?>} */] [string "aaa][variable-2 $aaa][string .aaa"]',
+ 10
+ );
+
+ MT('variable_interpolation_complex_syntax_3_1',
+ '[meta ]');
+
+ var m2 = build_recursive_monsters(
+ ['[string "a][variable-2 $]{[variable aaa] [operator +] ', ' [operator +] ', '}[string .a"]'],
+ '[comment /* }?>{{ */] [string "a?>}{{aa][variable-2 $aaa][string .a}a?>a"]',
+ 5
+ );
+
+ MT('variable_interpolation_complex_syntax_3_2',
+ '[meta ]');
+
+ function build_recursive_monsters_2(mf1, mf2, nt, t, n){
+ var monsters = [t];
+ for (var i = 1; i <= n; ++i)
+ monsters[i] = nt[0] + mf1[i - 1] + nt[1] + mf2[i - 1] + nt[2] + monsters[i - 1] + nt[3];
+ return monsters;
+ }
+
+ var m3 = build_recursive_monsters_2(
+ m1,
+ m2,
+ ['[string "a][variable-2 $]{[variable aaa] [operator +] ', ' [operator +] ', ' [operator +] ', '}[string .a"]'],
+ '[comment /* }?>{{ */] [string "a?>}{{aa][variable-2 $aaa][string .a}a?>a"]',
+ 4
+ );
+
+ MT('variable_interpolation_complex_syntax_3_3',
+ '[meta ]');
+})();
diff --git a/test/index.html b/test/index.html
index 76fd835f28..752971fe48 100644
--- a/test/index.html
+++ b/test/index.html
@@ -15,6 +15,8 @@
+
+
@@ -78,6 +80,7 @@
+
From ef2293517ab2d09b3e56b1967e1c683d583937a0 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Thu, 17 Apr 2014 16:16:57 +0200
Subject: [PATCH 113/127] [php mode] Follow up on
beb975f7e76c734044fa35a2c9a64b97f9eb5c94
Simplify some things, change a name.
Issue #2468
---
mode/php/php.js | 46 +++++++++++++++++-----------------------------
1 file changed, 17 insertions(+), 29 deletions(-)
diff --git a/mode/php/php.js b/mode/php/php.js
index 184293b62b..db3672d88f 100644
--- a/mode/php/php.js
+++ b/mode/php/php.js
@@ -21,30 +21,20 @@
};
}
- // Two helper functions for encapsList
- function matchFirst(list) {
- return function (stream) {
- for (var i = 0; i < list.length; ++i)
- if (stream.match(list[i][0]))
- return list[i][1];
- return false;
- };
- }
+ // Helper for stringWithEscapes
function matchSequence(list) {
- if (list.length == 0) return encapsList;
+ if (list.length == 0) return stringWithEscapes;
return function (stream, state) {
- var result = list[0](stream, state);
- if (result !== false) {
+ var patterns = list[0];
+ for (var i = 0; i < patterns.length; i++) if (stream.match(patterns[i][0])) {
state.tokenize = matchSequence(list.slice(1));
- return result;
- }
- else {
- state.tokenize = encapsList;
- return "string";
+ return patterns[i][1];
}
+ state.tokenize = stringWithEscapes;
+ return "string";
};
}
- function encapsList(stream, state) {
+ function stringWithEscapes(stream, state) {
var escaped = false, next, end = false;
if (stream.current() == '"') return "string";
@@ -61,20 +51,18 @@
if (stream.match("[", false)) {
// Match array operator
state.tokenize = matchSequence([
- matchFirst([["[", null]]),
- matchFirst([
- [/\d[\w\.]*/, "number"],
- [/\$[a-zA-Z_][a-zA-Z0-9_]*/, "variable-2"],
- [/[\w\$]+/, "variable"]
- ]),
- matchFirst([["]", null]])
+ [["[", null]],
+ [[/\d[\w\.]*/, "number"],
+ [/\$[a-zA-Z_][a-zA-Z0-9_]*/, "variable-2"],
+ [/[\w\$]+/, "variable"]],
+ [["]", null]]
]);
}
if (stream.match(/\-\>\w/, false)) {
// Match object operator
state.tokenize = matchSequence([
- matchFirst([["->", null]]),
- matchFirst([[/[\w]+/, "variable"]])
+ [["->", null]],
+ [[/[\w]+/, "variable"]]
]);
}
return "variable-2";
@@ -143,7 +131,7 @@
if (!state.phpEncapsStack)
state.phpEncapsStack = [];
state.phpEncapsStack.push(0);
- state.tokenize = encapsList;
+ state.tokenize = stringWithEscapes;
return state.tokenize(stream, state);
},
"{": function(_stream, state) {
@@ -154,7 +142,7 @@
"}": function(_stream, state) {
if (state.phpEncapsStack && state.phpEncapsStack.length > 0)
if (--state.phpEncapsStack[state.phpEncapsStack.length - 1] == 0)
- state.tokenize = encapsList;
+ state.tokenize = stringWithEscapes;
return false;
}
}
From 606f55f1f45bb80f69e007534bd51793a86fe750 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Tue, 22 Apr 2014 10:12:27 +0200
Subject: [PATCH 114/127] Wrap replaceSelections in an operation
Issue #2485
---
lib/codemirror.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/lib/codemirror.js b/lib/codemirror.js
index bd03fdb36f..63f83be779 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -6254,13 +6254,13 @@
}
return parts;
},
- replaceSelection: docMethodOp(function(code, collapse, origin) {
+ replaceSelection: function(code, collapse, origin) {
var dup = [];
for (var i = 0; i < this.sel.ranges.length; i++)
dup[i] = code;
this.replaceSelections(dup, collapse, origin || "+input");
- }),
- replaceSelections: function(code, collapse, origin) {
+ },
+ replaceSelections: docMethodOp(function(code, collapse, origin) {
var changes = [], sel = this.sel;
for (var i = 0; i < sel.ranges.length; i++) {
var range = sel.ranges[i];
@@ -6271,7 +6271,7 @@
makeChange(this, changes[i]);
if (newSel) setSelectionReplaceHistory(this, newSel);
else if (this.cm) ensureCursorVisible(this.cm);
- },
+ }),
undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}),
redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}),
undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}),
From afcbdb6b4cbbbd057706ff9e0eb4a4cec054c499 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Tue, 22 Apr 2014 10:23:01 +0200
Subject: [PATCH 115/127] Fix bug in posFromMouse for rectangular coords
It was returning negative values in the ch field.
Issue #2485
---
lib/codemirror.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/codemirror.js b/lib/codemirror.js
index 63f83be779..138f10d224 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -2507,7 +2507,7 @@
var coords = coordsChar(cm, x, y), line;
if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
- coords = Pos(coords.line, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff);
+ coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
}
return coords;
}
From d3ba3a2d73fd992d2ee5055ea1c47c95871bac78 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Date: Tue, 22 Apr 2014 10:33:55 +0200
Subject: [PATCH 116/127] Fix problem with drag-select not clearning multiple
cursors
Issue #2486
---
lib/codemirror.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/codemirror.js b/lib/codemirror.js
index 138f10d224..03ddeb3931 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -2644,6 +2644,7 @@
if (!addNew) {
ourIndex = 0;
setSelection(doc, new Selection([ourRange], 0), sel_mouse);
+ startSel = doc.sel;
} else if (ourIndex > -1) {
replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
} else {
From 0ffe3e9056a10442baef3cb50146144633ba19d4 Mon Sep 17 00:00:00 2001
From: Gergely Hegykozi
Date: Mon, 21 Apr 2014 16:57:59 +0200
Subject: [PATCH 117/127] [jinja2 mode] Improve
---
mode/jinja2/index.html | 36 ++++++------
mode/jinja2/jinja2.js | 146 +++++++++++++++++++++++++++++++++++++------------
2 files changed, 131 insertions(+), 51 deletions(-)
diff --git a/mode/jinja2/index.html b/mode/jinja2/index.html
index 66bf2ec60a..c99daf6c4a 100644
--- a/mode/jinja2/index.html
+++ b/mode/jinja2/index.html
@@ -25,22 +25,26 @@
Jinja2 mode
-<html style="color: green">
- <!-- this is a comment -->
- <head>
- <title>Jinja2 Example</title>
- </head>
- <body>
- <ul>
- {# this is a comment #}
- {%- for item in li -%}
- <li>
- {{ item.label }}
- </li>
- {% endfor -%}
- </ul>
- </body>
-</html>
+{# this is a comment #}
+{%- for item in li -%}
+ <li>{{ item.label }}</li>
+{% endfor -%}
+{{ item.sand == true and item.keyword == false ? 1 : 0 }}
+{{ app.get(55, 1.2, true) }}
+{% if app.get('_route') == ('_home') %}home{% endif %}
+{% if app.session.flashbag.has('message') %}
+ {% for message in app.session.flashbag.get('message') %}
+ {{ message.content }}
+ {% endfor %}
+{% endif %}
+{{ path('_home', {'section': app.request.get('section')}) }}
+{{ path('_home', {
+ 'section': app.request.get('section'),
+ 'boolean': true,
+ 'number': 55.33
+ })
+}}
+{% include ('test.incl.html.twig') %}
DOWNLOAD LATEST RELEASE
-
+
DONATE WITH PAYPAL
diff --git a/lib/codemirror.js b/lib/codemirror.js
index 0a07ed91ae..0ab217711e 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -7520,7 +7520,7 @@
// THE END
- CodeMirror.version = "4.0.4";
+ CodeMirror.version = "4.1.0";
return CodeMirror;
});
diff --git a/package.json b/package.json
index 39946f35f8..26d7053629 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "codemirror",
- "version":"4.0.4",
+ "version":"4.1.0",
"main": "lib/codemirror.js",
"description": "In-browser code editing made bearable",
"licenses": [{"type": "MIT",