From b92c57caa7da59901aa46325be9d15574030e26c Mon Sep 17 00:00:00 2001 From: Travis Heppe Date: Sat, 8 Mar 2014 19:57:05 -0800 Subject: [PATCH 001/127] Add some unit tests for enforcing the search behavior with 't' and 'f' from within macros. --- test/vim_test.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/vim_test.js b/test/vim_test.js index 3c675d0326..abb191f0d0 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -1764,6 +1764,24 @@ testVim('macro_space', function(cm, vim, helpers) { helpers.doKeys('@', 'a'); helpers.assertCursorAt(0, 8); }, { value: 'one line of text.'}); +testVim('macro_t_search', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('q', 'a', 't', 'e', 'q'); + helpers.assertCursorAt(0, 1); + helpers.doKeys('l', '@', 'a'); + helpers.assertCursorAt(0, 6); + helpers.doKeys('l', '@', 'a'); + helpers.assertCursorAt(0, 12); +}, { value: 'one line of text.'}); +testVim('macro_f_search', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('q', 'b', 'f', 'e', 'q'); + helpers.assertCursorAt(0, 2); + helpers.doKeys('@', 'b'); + helpers.assertCursorAt(0, 7); + helpers.doKeys('@', 'b'); + helpers.assertCursorAt(0, 13); +}, { value: 'one line of text.'}); testVim('macro_parens', function(cm, vim, helpers) { cm.setCursor(0, 0); helpers.doKeys('q', 'z', 'i'); From 2054ec8bc43c12b7b6ad903e38e4140e9d5efc67 Mon Sep 17 00:00:00 2001 From: Travis Heppe Date: Sun, 9 Mar 2014 23:43:14 -0700 Subject: [PATCH 002/127] account for Ex dialog prompts in search queries recorded into macros. --- keymap/vim.js | 40 +++++++++++++++++++++++++++++++++------- test/vim_test.js | 26 ++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index 07765f843f..b630b7c764 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -537,6 +537,7 @@ this.latestRegister = undefined; this.isPlaying = false; this.isRecording = false; + this.replaySearchQueries = []; this.onRecordingDone = undefined; this.lastInsertModeChanges = createInsertModeChanges(); } @@ -752,6 +753,7 @@ this.clear(); this.keyBuffer = [text || '']; this.insertModeChanges = []; + this.searchQueries = []; this.linewise = !!linewise; } Register.prototype = { @@ -770,9 +772,13 @@ pushInsertModeChanges: function(changes) { this.insertModeChanges.push(createInsertModeChanges(changes)); }, + pushSearchQuery: function(query) { + this.searchQueries.push(query); + }, clear: function() { this.keyBuffer = []; this.insertModeChanges = []; + this.searchQueries = []; this.linewise = false; }, toString: function() { @@ -1064,6 +1070,10 @@ function onPromptClose(query) { cm.scrollTo(originalScrollPos.left, originalScrollPos.top); handleQuery(query, true /** ignoreCase */, true /** smartCase */); + var macroModeState = vimGlobalState.macroModeState; + if (macroModeState.isRecording) { + logSearchQuery(macroModeState, query); + } } function onPromptKeyUp(_e, query) { var parsedQuery; @@ -1094,13 +1104,19 @@ } switch (command.searchArgs.querySrc) { case 'prompt': - showPrompt(cm, { - onClose: onPromptClose, - prefix: promptPrefix, - desc: searchPromptDesc, - onKeyUp: onPromptKeyUp, - onKeyDown: onPromptKeyDown - }); + var macroModeState = vimGlobalState.macroModeState; + if (macroModeState.isPlaying) { + var query = macroModeState.replaySearchQueries.shift(); + handleQuery(query, true /** ignoreCase */, false /** smartCase */); + } else { + showPrompt(cm, { + onClose: onPromptClose, + prefix: promptPrefix, + desc: searchPromptDesc, + onKeyUp: onPromptKeyUp, + onKeyDown: onPromptKeyDown + }); + } break; case 'wordUnderCursor': var word = expandWordUnderCursor(cm, false /** inclusive */, @@ -3922,6 +3938,7 @@ var keyBuffer = register.keyBuffer; var imc = 0; macroModeState.isPlaying = true; + macroModeState.replaySearchQueries = register.searchQueries.slice(0); for (var i = 0; i < keyBuffer.length; i++) { var text = keyBuffer[i]; var match, key; @@ -3960,6 +3977,15 @@ } } + function logSearchQuery(macroModeState, query) { + if (macroModeState.isPlaying) { return; } + var registerName = macroModeState.latestRegister; + var register = vimGlobalState.registerController.getRegister(registerName); + if (register) { + register.pushSearchQuery(query); + } + } + /** * Listens for changes made in insert mode. * Should only be active in insert mode. diff --git a/test/vim_test.js b/test/vim_test.js index abb191f0d0..0a82987389 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -1770,7 +1770,7 @@ testVim('macro_t_search', function(cm, vim, helpers) { helpers.assertCursorAt(0, 1); helpers.doKeys('l', '@', 'a'); helpers.assertCursorAt(0, 6); - helpers.doKeys('l', '@', 'a'); + helpers.doKeys('l', ';'); helpers.assertCursorAt(0, 12); }, { value: 'one line of text.'}); testVim('macro_f_search', function(cm, vim, helpers) { @@ -1779,9 +1779,31 @@ testVim('macro_f_search', function(cm, vim, helpers) { helpers.assertCursorAt(0, 2); helpers.doKeys('@', 'b'); helpers.assertCursorAt(0, 7); - helpers.doKeys('@', 'b'); + helpers.doKeys(';'); + helpers.assertCursorAt(0, 13); +}, { value: 'one line of text.'}); +testVim('macro_slash_search', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('q', 'c'); + cm.openDialog = helpers.fakeOpenDialog('e'); + helpers.doKeys('/', 'q'); + helpers.assertCursorAt(0, 2); + helpers.doKeys('@', 'c'); + helpers.assertCursorAt(0, 7); + helpers.doKeys('n'); helpers.assertCursorAt(0, 13); }, { value: 'one line of text.'}); +testVim('macro_multislash_search', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('q', 'd'); + cm.openDialog = helpers.fakeOpenDialog('e'); + helpers.doKeys('/'); + cm.openDialog = helpers.fakeOpenDialog('t'); + helpers.doKeys('/', 'q'); + helpers.assertCursorAt(0, 12); + helpers.doKeys('@', 'd'); + helpers.assertCursorAt(0, 15); +}, { value: 'one line of text to rule them all.'}); testVim('macro_parens', function(cm, vim, helpers) { cm.setCursor(0, 0); helpers.doKeys('q', 'z', 'i'); From 238015d4235920540dbfdd56bed738af0a9674a8 Mon Sep 17 00:00:00 2001 From: binny Date: Mon, 10 Mar 2014 05:49:17 +0530 Subject: [PATCH 003/127] : and . registers implemented --- keymap/vim.js | 16 ++++++++++++++-- test/vim_test.js | 13 +++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index b630b7c764..a2cefc4401 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -384,7 +384,7 @@ var specialKeys = ['Left', 'Right', 'Up', 'Down', 'Space', 'Backspace', 'Esc', 'Home', 'End', 'PageUp', 'PageDown', 'Enter']; var validMarks = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['<', '>']); - var validRegisters = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['-', '"']); + var validRegisters = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['-', '"','.',':']); function isLine(cm, line) { return line >= cm.firstLine() && line <= cm.lastLine(); @@ -797,6 +797,8 @@ function RegisterController(registers) { this.registers = registers; this.unnamedRegister = registers['"'] = new Register(); + registers['.'] = new Register(); + registers[':'] = new Register(); } RegisterController.prototype = { pushText: function(registerName, operator, text, linewise) { @@ -3200,10 +3202,14 @@ Vim.ExCommandDispatcher.prototype = { processCommand: function(cm, input) { var vim = cm.state.vim; + var commandHistoryRegister = vimGlobalState.registerController.getRegister(':'); + var previousCommand = commandHistoryRegister.toString(); if (vim.visualMode) { exitVisualMode(cm); } var inputStream = new CodeMirror.StringStream(input); + // update ": with the latest command whether valid or invalid + commandHistoryRegister.setText(inputStream.string); var params = {}; params.input = input; try { @@ -3222,6 +3228,9 @@ var command = this.matchCommand_(params.commandName); if (command) { commandName = command.name; + if (commandName == 'registers') { + commandHistoryRegister.setText(previousCommand); + } this.parseCommandArgs_(inputStream, params, command); if (command.type == 'exToKey') { // Handle Ex to Key mapping. @@ -3513,7 +3522,7 @@ continue; } var register = registers[registerName] || new Register(); - regInfo += '"' + registerName + ' ' + register.text + '
'; + regInfo += '"' + registerName + ' ' + register.toString() + '
'; } } showConfirm(cm, regInfo); @@ -3888,6 +3897,7 @@ function exitInsertMode(cm) { var vim = cm.state.vim; var macroModeState = vimGlobalState.macroModeState; + var imcRegister = vimGlobalState.registerController.getRegister('.'); var isPlaying = macroModeState.isPlaying; if (!isPlaying) { cm.off('change', onChange); @@ -3906,6 +3916,8 @@ cm.setOption('keyMap', 'vim'); cm.setOption('disableInput', true); cm.toggleOverwrite(false); // exit replace mode if we were in it. + // update the ". register before exiting insert mode + imcRegister.setText(macroModeState.lastInsertModeChanges.changes.join('')); CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"}); if (macroModeState.isRecording) { logInsertModeChange(macroModeState); diff --git a/test/vim_test.js b/test/vim_test.js index 0a82987389..e57cc22d53 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -1879,6 +1879,19 @@ testVim('macro_register', function(cm, vim, helpers) { }); helpers.doKeys(':'); }, { value: ''}); +testVim('ro_registers', function(cm,vim,helpers) { + cm.setCursor(0,0); + helpers.doKeys('i'); + cm.replaceRange('foo',cm.getCursor()); + helpers.doInsertModeKeys('Esc'); + helpers.doEx('sort'); + cm.openDialog = helpers.fakeOpenDialog('registers'); + cm.openNotification = helpers.fakeOpenNotification(function(text) { + is(/\.\s+foo/.test(text)); + is(/:\s+sort/.test(text)); + }); + helpers.doKeys(':'); +}, {value: ''}); testVim('.', function(cm, vim, helpers) { cm.setCursor(0, 0); helpers.doKeys('2', 'd', 'w'); From dd873fb73bc10d75f7df70c3e48983b4f4e2c5e8 Mon Sep 17 00:00:00 2001 From: binny Date: Tue, 11 Mar 2014 03:57:04 +0530 Subject: [PATCH 004/127] ro_registers with corrections --- keymap/vim.js | 12 ++++++------ test/vim_test.js | 12 +++++++++--- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index a2cefc4401..bb6c55b12d 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -384,7 +384,7 @@ var specialKeys = ['Left', 'Right', 'Up', 'Down', 'Space', 'Backspace', 'Esc', 'Home', 'End', 'PageUp', 'PageDown', 'Enter']; var validMarks = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['<', '>']); - var validRegisters = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['-', '"','.',':']); + var validRegisters = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['-', '"', '.', ':']); function isLine(cm, line) { return line >= cm.firstLine() && line <= cm.lastLine(); @@ -3194,7 +3194,7 @@ { name: 'substitute', shortName: 's' }, { name: 'nohlsearch', shortName: 'noh' }, { name: 'delmarks', shortName: 'delm' }, - { name: 'registers', shortName: 'reg' } + { name: 'registers', shortName: 'reg', excludeFromCommandHistory: true } ]; Vim.ExCommandDispatcher = function() { this.buildCommandMap_(); @@ -3209,7 +3209,7 @@ } var inputStream = new CodeMirror.StringStream(input); // update ": with the latest command whether valid or invalid - commandHistoryRegister.setText(inputStream.string); + commandHistoryRegister.setText(input); var params = {}; params.input = input; try { @@ -3228,7 +3228,7 @@ var command = this.matchCommand_(params.commandName); if (command) { commandName = command.name; - if (commandName == 'registers') { + if (command.excludeFromCommandHistory) { commandHistoryRegister.setText(previousCommand); } this.parseCommandArgs_(inputStream, params, command); @@ -3897,7 +3897,7 @@ function exitInsertMode(cm) { var vim = cm.state.vim; var macroModeState = vimGlobalState.macroModeState; - var imcRegister = vimGlobalState.registerController.getRegister('.'); + var insertModeChangeRegister = vimGlobalState.registerController.getRegister('.'); var isPlaying = macroModeState.isPlaying; if (!isPlaying) { cm.off('change', onChange); @@ -3917,7 +3917,7 @@ cm.setOption('disableInput', true); cm.toggleOverwrite(false); // exit replace mode if we were in it. // update the ". register before exiting insert mode - imcRegister.setText(macroModeState.lastInsertModeChanges.changes.join('')); + insertModeChangeRegister.setText(macroModeState.lastInsertModeChanges.changes.join('')); CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"}); if (macroModeState.isRecording) { logInsertModeChange(macroModeState); diff --git a/test/vim_test.js b/test/vim_test.js index e57cc22d53..b51d47cd8b 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -1879,16 +1879,22 @@ testVim('macro_register', function(cm, vim, helpers) { }); helpers.doKeys(':'); }, { value: ''}); -testVim('ro_registers', function(cm,vim,helpers) { +testVim('._register', function(cm,vim,helpers) { cm.setCursor(0,0); helpers.doKeys('i'); cm.replaceRange('foo',cm.getCursor()); helpers.doInsertModeKeys('Esc'); - helpers.doEx('sort'); cm.openDialog = helpers.fakeOpenDialog('registers'); cm.openNotification = helpers.fakeOpenNotification(function(text) { is(/\.\s+foo/.test(text)); - is(/:\s+sort/.test(text)); + }); + helpers.doKeys(':'); +}, {value: ''}); +testVim(':_register', function(cm,vim,helpers) { + helpers.doEx('bar'); + cm.openDialog = helpers.fakeOpenDialog('registers'); + cm.openNotification = helpers.fakeOpenNotification(function(text) { + is(/:\s+bar/.test(text)); }); helpers.doKeys(':'); }, {value: ''}); From af4dedbf880673a2e616f9c180f54aa9c214cc60 Mon Sep 17 00:00:00 2001 From: Travis Heppe Date: Sat, 8 Mar 2014 19:57:05 -0800 Subject: [PATCH 005/127] [dylan mode] Add --- doc/compress.html | 1 + mode/dylan/dylan.js | 302 ++++++++++++++++++++++++++++++++++++ mode/dylan/index.html | 417 ++++++++++++++++++++++++++++++++++++++++++++++++++ mode/index.html | 1 + mode/meta.js | 1 + 5 files changed, 722 insertions(+) create mode 100644 mode/dylan/dylan.js create mode 100755 mode/dylan/index.html diff --git a/doc/compress.html b/doc/compress.html index 9e86230a94..d2ac91b1c0 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -92,6 +92,7 @@ + diff --git a/mode/dylan/dylan.js b/mode/dylan/dylan.js new file mode 100644 index 0000000000..a8e584e196 --- /dev/null +++ b/mode/dylan/dylan.js @@ -0,0 +1,302 @@ +CodeMirror.defineMode("dylan", function (config, parserConfig) { + // Words + var words = { + // Words that introduce unnamed definitions like "define interface" + unnamedDefinition: ["interface"], + + // Words that introduce simple named definitions like "define library" + namedDefinition: ["module", "library", "macro", + "C-struct", "C-union", + "C-function", "C-callable-wrapper" + ], + + // Words that introduce type definitions like "define class". + // These are also parameterized like "define method" and are + // appended to otherParameterizedDefinitionWords + typeParameterizedDefinition: ["class", "C-subtype", "C-mapped-subtype"], + + // Words that introduce trickier definitions like "define method". + // These require special definitions to be added to startExpressions + otherParameterizedDefinition: ["method", "function", + "C-variable", "C-address" + ], + + // Words that introduce module constant definitions. + // These must also be simple definitions and are + // appended to otherSimpleDefinitionWords + constantSimpleDefinition: ["constant"], + + // Words that introduce module variable definitions. + // These must also be simple definitions and are + // appended to otherSimpleDefinitionWords + variableSimpleDefinition: ["variable"], + + // Other words that introduce simple definitions + // (without implicit bodies). + otherSimpleDefinition: ["generic", "domain", + "C-pointer-type", + "table" + ], + + // Words that begin statements with implicit bodies. + statement: ["if", "block", "begin", "method", "case", + "for", "select", "when", "unless", "until", + "while", "iterate", "profiling", "dynamic-bind" + ], + + // Patterns that act as separators in compound statements. + // This may include any general pattern that must be indented + // specially. + separator: ["finally", "exception", "cleanup", "else", + "elseif", "afterwards" + ], + + // Keywords that do not require special indentation handling, + // but which should be highlighted + other: ["above", "below", "by", "from", "handler", "in", + "instance", "let", "local", "otherwise", "slot", + "subclass", "then", "to", "keyed-by", "virtual" + ], + + // Condition signaling function calls + signalingCalls: ["signal", "error", "cerror", + "break", "check-type", "abort" + ] + }; + + words["otherDefinition"] = + words["unnamedDefinition"] + .concat(words["namedDefinition"]) + .concat(words["otherParameterizedDefinition"]); + + words["definition"] = + words["typeParameterizedDefinition"] + .concat(words["otherDefinition"]); + + words["parameterizedDefinition"] = + words["typeParameterizedDefinition"] + .concat(words["otherParameterizedDefinition"]); + + words["simpleDefinition"] = + words["constantSimpleDefinition"] + .concat(words["variableSimpleDefinition"]) + .concat(words["otherSimpleDefinition"]); + + words["keyword"] = + words["statement"] + .concat(words["separator"]) + .concat(words["other"]); + + // Patterns + var symbolPattern = "[-_a-zA-Z?!*@<>$%]+"; + var symbol = new RegExp("^" + symbolPattern); + var patterns = { + // Symbols with special syntax + symbolKeyword: symbolPattern + ":", + symbolClass: "<" + symbolPattern + ">", + symbolGlobal: "\\*" + symbolPattern + "\\*", + symbolConstant: "\\$" + symbolPattern + }; + var patternStyles = { + symbolKeyword: "atom", + symbolClass: "tag", + symbolGlobal: "variable-2", + symbolConstant: "variable-3" + }; + + // Compile all patterns to regular expressions + for (var patternName in patterns) + if (patterns.hasOwnProperty(patternName)) + patterns[patternName] = new RegExp("^" + patterns[patternName]); + + // Names beginning "with-" and "without-" are commonly + // used as statement macro + patterns["keyword"] = [/^with(?:out)?-[-_a-zA-Z?!*@<>$%]+/]; + + var styles = {}; + styles["keyword"] = "keyword"; + styles["definition"] = "def"; + styles["simpleDefinition"] = "def"; + styles["signalingCalls"] = "builtin"; + + // protected words lookup table + var wordLookup = {}; + var styleLookup = {}; + + [ + "keyword", + "definition", + "simpleDefinition", + "signalingCalls" + ].forEach(function (type) { + words[type].forEach(function (word) { + wordLookup[word] = type; + styleLookup[word] = styles[type]; + }); + }); + + + function chain(stream, state, f) { + state.tokenize = f; + return f(stream, state); + } + + var type, content; + + function ret(_type, style, _content) { + type = _type; + content = _content; + return style; + } + + function indent(_stream, state) { + state.currentIndent++; + } + + function dedent(_stream, state) { + state.currentIndent--; + } + + function tokenBase(stream, state) { + // String + var ch = stream.peek(); + if (ch == "'" || ch == '"') { + stream.next(); + return chain(stream, state, tokenString(ch, "string", "string")); + } + // Comment + else if (ch == "/") { + stream.next(); + if (stream.eat("*")) { + return chain(stream, state, tokenComment); + } else if (stream.eat("/")) { + stream.skipToEnd(); + return ret("comment", "comment"); + } else { + stream.skipTo(" "); + return ret("operator", "operator"); + } + } + // Decimal + else if (/\d/.test(ch)) { + stream.match(/^\d*(?:\.\d*)?(?:e[+\-]?\d+)?/); + return ret("number", "number"); + } + // Hash + else if (ch == "#") { + stream.next(); + // Symbol with string syntax + ch = stream.peek(); + if (ch == '"') { + stream.next(); + return chain(stream, state, tokenString('"', "symbol", "string-2")); + } + // Binary number + else if (ch == "b") { + stream.next(); + stream.eatWhile(/[01]/); + return ret("number", "number"); + } + // Hex number + else if (ch == "x") { + stream.next(); + stream.eatWhile(/[\da-f]/i); + return ret("number", "number"); + } + // Octal number + else if (ch == "o") { + stream.next(); + stream.eatWhile(/[0-7]/); + return ret("number", "number"); + } + // Hash symbol + else { + stream.eatWhile(/[-a-zA-Z]/); + return ret("hash", "keyword"); + } + } else if (stream.match("end")) { + dedent(stream, state); + return ret("end", "keyword"); + } + for (var name in patterns) { + if (patterns.hasOwnProperty(name)) { + var pattern = patterns[name]; + if ((pattern instanceof Array && pattern.some(function (p) { + return stream.match(p); + })) || stream.match(pattern)) + return ret(name, patternStyles[name], stream.current()); + } + } + if (stream.match("define")) { + indent(stream, state); + return ret("definition", "def"); + } else { + stream.eatWhile(/[\w\-]/); + // Keyword + if (wordLookup[stream.current()]) { + return ret(wordLookup[stream.current()], styleLookup[stream.current()], stream.current()); + } else if (stream.current().match(symbol)) { + return ret("variable", "variable"); + } else { + stream.next(); + return ret("other", "variable-2"); + } + } + } + + function tokenComment(stream, state) { + var maybeEnd = false, + ch; + while ((ch = stream.next())) { + if (ch == "/" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return ret("comment", "comment"); + } + + function tokenString(quote, type, style) { + return function (stream, state) { + var next, end = false; + while ((next = stream.next()) != null) { + if (next == quote) { + end = true; + break; + } + } + if (end) + state.tokenize = tokenBase; + return ret(type, style); + }; + } + + // Interface + return { + startState: function (baseColumn) { + return { + tokenize: tokenBase, + currentIndent: 0 + }; + }, + token: function (stream, state) { + if (stream.eatSpace()) + return null; + var style = state.tokenize(stream, state); + return style; + }, + /* + // This isn't working for me. + indent: function (state, textAfter) { + if (state.tokenize != tokenBase) + return 0; + return state.currentIndent * config.indentUnit; + }, + */ + blockCommentStart: "/*", + blockCommentEnd: "*/" + }; +}); + +CodeMirror.defineMIME("text/x-dylan", "dylan"); diff --git a/mode/dylan/index.html b/mode/dylan/index.html new file mode 100755 index 0000000000..d4f0a2cc6e --- /dev/null +++ b/mode/dylan/index.html @@ -0,0 +1,417 @@ + + +CodeMirror: Dylan mode + + + + + + + + + + + + +
+

Dylan mode

+ + +
+ + + +

MIME types defined: text/x-dylan.

+
diff --git a/mode/index.html b/mode/index.html index 26ea93ef02..1e7e59a5b9 100644 --- a/mode/index.html +++ b/mode/index.html @@ -42,6 +42,7 @@
  • D
  • diff
  • DTD
  • +
  • Dylan
  • ECL
  • Eiffel
  • Erlang
  • diff --git a/mode/meta.js b/mode/meta.js index a3989c5538..c9498644ca 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -14,6 +14,7 @@ CodeMirror.modeInfo = [ {name: 'D', mime: 'text/x-d', mode: 'd'}, {name: 'diff', mime: 'text/x-diff', mode: 'diff'}, {name: 'DTD', mime: 'application/xml-dtd', mode: 'dtd'}, + {name: 'Dylan', mime: 'text/x-dylan', mode: 'dylan'}, {name: 'ECL', mime: 'text/x-ecl', mode: 'ecl'}, {name: 'Eiffel', mime: 'text/x-eiffel', mode: 'eiffel'}, {name: 'Erlang', mime: 'text/x-erlang', mode: 'erlang'}, From 4d9be849acb748ba4792f2ef6d307c3a2adb3c5c Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 11 Mar 2014 15:50:49 +0100 Subject: [PATCH 006/127] [dylan mode] Clean up Issue #2352 --- mode/dylan/dylan.js | 32 +++++++------------------------- mode/dylan/index.html | 10 ---------- 2 files changed, 7 insertions(+), 35 deletions(-) diff --git a/mode/dylan/dylan.js b/mode/dylan/dylan.js index a8e584e196..d81ef0cbcb 100644 --- a/mode/dylan/dylan.js +++ b/mode/dylan/dylan.js @@ -1,4 +1,4 @@ -CodeMirror.defineMode("dylan", function (config, parserConfig) { +CodeMirror.defineMode("dylan", function(_config) { // Words var words = { // Words that introduce unnamed definitions like "define interface" @@ -128,8 +128,8 @@ CodeMirror.defineMode("dylan", function (config, parserConfig) { "definition", "simpleDefinition", "signalingCalls" - ].forEach(function (type) { - words[type].forEach(function (word) { + ].forEach(function(type) { + words[type].forEach(function(word) { wordLookup[word] = type; styleLookup[word] = styles[type]; }); @@ -149,14 +149,6 @@ CodeMirror.defineMode("dylan", function (config, parserConfig) { return style; } - function indent(_stream, state) { - state.currentIndent++; - } - - function dedent(_stream, state) { - state.currentIndent--; - } - function tokenBase(stream, state) { // String var ch = stream.peek(); @@ -215,20 +207,18 @@ CodeMirror.defineMode("dylan", function (config, parserConfig) { return ret("hash", "keyword"); } } else if (stream.match("end")) { - dedent(stream, state); return ret("end", "keyword"); } for (var name in patterns) { if (patterns.hasOwnProperty(name)) { var pattern = patterns[name]; - if ((pattern instanceof Array && pattern.some(function (p) { + if ((pattern instanceof Array && pattern.some(function(p) { return stream.match(p); })) || stream.match(pattern)) return ret(name, patternStyles[name], stream.current()); } } if (stream.match("define")) { - indent(stream, state); return ret("definition", "def"); } else { stream.eatWhile(/[\w\-]/); @@ -258,7 +248,7 @@ CodeMirror.defineMode("dylan", function (config, parserConfig) { } function tokenString(quote, type, style) { - return function (stream, state) { + return function(stream, state) { var next, end = false; while ((next = stream.next()) != null) { if (next == quote) { @@ -274,26 +264,18 @@ CodeMirror.defineMode("dylan", function (config, parserConfig) { // Interface return { - startState: function (baseColumn) { + startState: function() { return { tokenize: tokenBase, currentIndent: 0 }; }, - token: function (stream, state) { + token: function(stream, state) { if (stream.eatSpace()) return null; var style = state.tokenize(stream, state); return style; }, - /* - // This isn't working for me. - indent: function (state, textAfter) { - if (state.tokenize != tokenBase) - return 0; - return state.currentIndent * config.indentUnit; - }, - */ blockCommentStart: "/*", blockCommentEnd: "*/" }; diff --git a/mode/dylan/index.html b/mode/dylan/index.html index d4f0a2cc6e..049f93cc63 100755 --- a/mode/dylan/index.html +++ b/mode/dylan/index.html @@ -55,7 +55,6 @@ define open generic locator-extension (locator :: ) => (extension :: false-or()); - /// Locator classes define open abstract class () @@ -104,7 +103,6 @@ name: name) end method make; - /// Locator coercion //---*** andrewa: This caching scheme doesn't work yet, so disable it. @@ -154,7 +152,6 @@ end end method as; - /// Locator conditions define class (, ) @@ -167,7 +164,6 @@ format-arguments: format-arguments)) end function locator-error; - /// Useful locator protocols define open generic locator-test @@ -209,7 +205,6 @@ end end method locator-directory; - /// Simplify locator define open generic simplify-locator @@ -250,7 +245,6 @@ end end method simplify-locator; - /// Subdirectory locator define open generic subdirectory-locator @@ -268,7 +262,6 @@ relative?: locator.locator-relative?) end method subdirectory-locator; - /// Relative locator define open generic relative-locator @@ -330,14 +323,12 @@ end end method relative-locator; - /// Merge locators define open generic merge-locators (locator :: , from-locator :: ) => (merged-locator :: ); - /// Merge locators define method merge-locators @@ -386,7 +377,6 @@ end end method merge-locators; - /// Locator protocols define sideways method supports-open-locator? From 0e857ad2bbb90a1f804f3be20d0995f055bedbb0 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 12 Mar 2014 13:49:10 +0100 Subject: [PATCH 007/127] [real-world uses] Add TagSpaces --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 661c556c21..08f0267856 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -119,6 +119,7 @@
  • Snippets.pro (code snippet sharing)
  • SolidShops (hosted e-commerce platform)
  • SQLFiddle (SQL playground)
  • +
  • TagSpaces (personal data manager)
  • The File Tree (collab editor)
  • TileMill (map design tool)
  • Toolsverse Data Explorer (database management)
  • From 4eca7048c5cc2ff5f4505e8cd6d5bf4e8fb4c943 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 12 Mar 2014 16:25:59 +0100 Subject: [PATCH 008/127] [xml mode] Style brackets with extra style Add tests. Adjust addons that depended on previous token structure. Also improve indentation around implicit end tags in HTML. Issue #2176 Issue #2333 --- addon/hint/xml-hint.js | 28 +++++++++++------ mode/xml/test.js | 43 ++++++++++++++++++++++++++ mode/xml/xml.js | 83 ++++++++++++++++++++++++++++++++++---------------- test/index.html | 1 + 4 files changed, 118 insertions(+), 37 deletions(-) create mode 100644 mode/xml/test.js diff --git a/addon/hint/xml-hint.js b/addon/hint/xml-hint.js index 69f2b771fe..f93db7a71e 100644 --- a/addon/hint/xml-hint.js +++ b/addon/hint/xml-hint.js @@ -11,22 +11,30 @@ var inner = CodeMirror.innerMode(cm.getMode(), token.state); if (inner.mode.name != "xml") return; var result = [], replaceToken = false, prefix; - var isTag = token.string.charAt(0) == "<"; - if (!inner.state.tagName || isTag) { // Tag completion - if (isTag) { - prefix = token.string.slice(1); - replaceToken = true; - } + var tag = /\btag\b/.test(token.type), tagName = tag && /^\w/.test(token.string), tagStart; + if (tagName) { + var before = cm.getLine(cur.line).slice(Math.max(0, token.start - 2), token.start); + var tagType = /<\/$/.test(before) ? "close" : /<$/.test(before) ? "open" : null; + if (tagType) tagStart = token.start - (tagType == "close" ? 2 : 1); + } else if (tag && token.string == "<") { + tagType = "open"; + } else if (tag && token.string == ""); } else { // Attribute completion @@ -59,7 +67,7 @@ } return { list: result, - from: replaceToken ? Pos(cur.line, token.start) : cur, + from: replaceToken ? Pos(cur.line, tagStart == null ? token.start : tagStart) : cur, to: replaceToken ? Pos(cur.line, token.end) : cur }; } diff --git a/mode/xml/test.js b/mode/xml/test.js new file mode 100644 index 0000000000..e0dfde0f25 --- /dev/null +++ b/mode/xml/test.js @@ -0,0 +1,43 @@ +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "xml"), mname = "xml"; + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), mname); } + + MT("matching", + "[tag&bracket <][tag top][tag&bracket >]", + " text", + " [tag&bracket <][tag inner][tag&bracket />]", + "[tag&bracket ]"); + + MT("nonmatching", + "[tag&bracket <][tag top][tag&bracket >]", + " [tag&bracket <][tag inner][tag&bracket />]", + " [tag&bracket ]"); + + MT("doctype", + "[meta ]", + "[tag&bracket <][tag top][tag&bracket />]"); + + MT("cdata", + "[tag&bracket <][tag top][tag&bracket >]", + " [atom ]", + "[tag&bracket ]"); + + // HTML tests + mode = CodeMirror.getMode({indentUnit: 2}, "text/html"); mname = "html"; + + MT("selfclose", + "[tag&bracket <][tag html][tag&bracket >]", + " [tag&bracket <][tag link] [attribute rel]=[string stylesheet] [attribute href]=[string \"/foobar\"][tag&bracket >]", + "[tag&bracket ]"); + + MT("list", + "[tag&bracket <][tag ol][tag&bracket >]", + " [tag&bracket <][tag li][tag&bracket >]one", + " [tag&bracket <][tag li][tag&bracket >]two", + "[tag&bracket ]"); + + MT("valueless", + "[tag&bracket <][tag input] [attribute type]=[string checkbox] [attribute checked][tag&bracket />]"); + +})(); diff --git a/mode/xml/xml.js b/mode/xml/xml.js index d9b04e89e1..1fbbbddd72 100644 --- a/mode/xml/xml.js +++ b/mode/xml/xml.js @@ -48,7 +48,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { var alignCDATA = parserConfig.alignCDATA; // Return variables for tokenizers - var tagName, type, setStyle; + var type, setStyle; function inText(stream, state) { function chain(parser) { @@ -75,15 +75,9 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { state.tokenize = inBlock("meta", "?>"); return "meta"; } else { - var isClose = stream.eat("/"); - tagName = ""; - var c; - while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c; - if (Kludges.caseFold) tagName = tagName.toLowerCase(); - if (!tagName) return "tag error"; - type = isClose ? "closeTag" : "openTag"; + type = stream.eat("/") ? "closeTag" : "openTag"; state.tokenize = inTag; - return "tag"; + return "tag bracket"; } } else if (ch == "&") { var ok; @@ -108,7 +102,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { if (ch == ">" || (ch == "/" && stream.eat(">"))) { state.tokenize = inText; type = ch == ">" ? "endTag" : "selfcloseTag"; - return "tag"; + return "tag bracket"; } else if (ch == "=") { type = "equals"; return null; @@ -123,7 +117,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { state.stringStartCol = stream.column(); return state.tokenize(stream, state); } else { - stream.eatWhile(/[^\s\u00a0=<>\"\']/); + stream.eatWhile(/[^\s\u00a0=<>\"\'\/]/); return "word"; } } @@ -203,24 +197,40 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { function baseState(type, stream, state) { if (type == "openTag") { - state.tagName = tagName; state.tagStart = stream.column(); - return attrState; + return tagNameState; } else if (type == "closeTag") { - var err = false; - if (state.context) { - if (state.context.tagName != tagName) { - if (Kludges.implicitlyClosed.hasOwnProperty(state.context.tagName)) - popContext(state); - err = !state.context || state.context.tagName != tagName; - } + return closeTagNameState; + } else { + return baseState; + } + } + function tagNameState(type, stream, state) { + if (type == "word") { + state.tagName = stream.current(); + setStyle = "tag"; + return attrState; + } else { + setStyle = "error"; + return tagNameState; + } + } + function closeTagNameState(type, stream, state) { + if (type == "word") { + var tagName = stream.current(); + if (state.context && state.context.tagName != tagName && + Kludges.implicitlyClosed.hasOwnProperty(state.context.tagName)) + popContext(state); + if (state.context && state.context.tagName == tagName) { + setStyle = "tag"; + return closeState; } else { - err = true; + setStyle = "tag error"; + return closeStateErr; } - if (err) setStyle = "error"; - return err ? closeStateErr : closeState; } else { - return baseState; + setStyle = "error"; + return closeStateErr; } } function closeState(type, _stream, state) { @@ -285,7 +295,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { state.indented = stream.indentation(); if (stream.eatSpace()) return null; - tagName = type = null; + type = null; var style = state.tokenize(stream, state); if ((style || type) && style != "comment") { setStyle = null; @@ -313,8 +323,27 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { return state.tagStart + indentUnit * multilineTagIndentFactor; } if (alignCDATA && / + From da218666d28c8ddd373e839be9d68f84fd99e789 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 12 Mar 2014 16:35:01 +0100 Subject: [PATCH 009/127] [haml mode] Fix test that depended on XML mode token structure --- mode/haml/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/haml/test.js b/mode/haml/test.js index 163b09f8dd..75d0e7710f 100644 --- a/mode/haml/test.js +++ b/mode/haml/test.js @@ -28,7 +28,7 @@ "[tag %a]([variable title][operator =][string \"test\"]){[atom :title] [operator =>] [string \"test\"]}"); MT("htmlCode", - "[tag

    ]Title[tag

    ]"); + "[tag&bracket <][tag h1][tag&bracket >]Title[tag&bracket ]"); MT("rubyBlock", "[operator =][variable-2 @item]"); From c6700d8608e76f0506b25831d953ade26589345a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 13 Mar 2014 11:35:24 +0100 Subject: [PATCH 010/127] Fix context menu (when no selection) on IE --- lib/codemirror.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 7d43ac49ed..ee1e418b65 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2242,8 +2242,9 @@ window.CodeMirror = (function() { var oldCSS = display.input.style.cssText; display.inputDiv.style.position = "absolute"; display.input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) + - "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: transparent; outline: none;" + - "border-width: 0; outline: none; overflow: hidden; opacity: .05; -ms-opacity: .05; filter: alpha(opacity=5);"; + "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " + + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + + "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"; focusInput(cm); resetInput(cm, true); // Adds "Select all" to context menu in FF From a67f6e1b0ee652b50c7a2ab8c877220c647395b2 Mon Sep 17 00:00:00 2001 From: binny Date: Thu, 13 Mar 2014 15:07:30 +0530 Subject: [PATCH 011/127] [vim] Update :substitute to use last substitution if no arguments --- keymap/vim.js | 68 ++++++++++++++++++++++++++++++++------------------------ test/vim_test.js | 7 ++++++ 2 files changed, 46 insertions(+), 29 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index bb6c55b12d..899c6c0e83 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -603,6 +603,8 @@ searchQuery: null, // Whether we are searching backwards. searchIsReversed: false, + // Replace part of the last substituted pattern + lastSubstituteReplacePart: undefined, jumpList: createCircularJumpList(), macroModeState: new MacroModeState, // Recording latest f, t, F or T motion command. @@ -3608,38 +3610,41 @@ 'any other getSearchCursor implementation.'); } var argString = params.argString; - var slashes = findUnescapedSlashes(argString); - if (slashes[0] !== 0) { - showConfirm(cm, 'Substitutions should be of the form ' + - ':s/pattern/replace/'); - return; - } - var regexPart = argString.substring(slashes[0] + 1, slashes[1]); + var slashes = argString ? findUnescapedSlashes(argString) : []; var replacePart = ''; - var flagsPart; - var count; - var confirm = false; // Whether to confirm each replace. - if (slashes[1]) { - replacePart = argString.substring(slashes[1] + 1, slashes[2]); - if (getOption('pcre')) { - replacePart = unescapeRegexReplace(replacePart); - } else { - replacePart = translateRegexReplace(replacePart); + if (slashes.length) { + if (slashes[0] !== 0) { + showConfirm(cm, 'Substitutions should be of the form ' + + ':s/pattern/replace/'); + return; } - } - if (slashes[2]) { - // After the 3rd slash, we can have flags followed by a space followed - // by count. - var trailing = argString.substring(slashes[2] + 1).split(' '); - flagsPart = trailing[0]; - count = parseInt(trailing[1]); - } - if (flagsPart) { - if (flagsPart.indexOf('c') != -1) { - confirm = true; - flagsPart.replace('c', ''); + var regexPart = argString.substring(slashes[0] + 1, slashes[1]); + var flagsPart; + var count; + var confirm = false; // Whether to confirm each replace. + if (slashes[1]) { + replacePart = argString.substring(slashes[1] + 1, slashes[2]); + if (getOption('pcre')) { + replacePart = unescapeRegexReplace(replacePart); + } else { + replacePart = translateRegexReplace(replacePart); + } + vimGlobalState.lastSubstituteReplacePart = replacePart; + } + if (slashes[2]) { + // After the 3rd slash, we can have flags followed by a space followed + // by count. + var trailing = argString.substring(slashes[2] + 1).split(' '); + flagsPart = trailing[0]; + count = parseInt(trailing[1]); + } + if (flagsPart) { + if (flagsPart.indexOf('c') != -1) { + confirm = true; + flagsPart.replace('c', ''); + } + regexPart = regexPart + '/' + flagsPart; } - regexPart = regexPart + '/' + flagsPart; } if (regexPart) { // If regex part is empty, then use the previous query. Otherwise use @@ -3652,6 +3657,11 @@ return; } } + replacePart = replacePart || vimGlobalState.lastSubstituteReplacePart; + if (replacePart === undefined) { + showConfirm(cm, 'No previous substitute regular expression'); + return; + } var state = getSearchState(cm); var query = state.getQuery(); var lineStart = (params.line !== undefined) ? params.line : cm.getCursor().line; diff --git a/test/vim_test.js b/test/vim_test.js index b51d47cd8b..4d9525e15e 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -2550,6 +2550,13 @@ testVim('ex_substitute_javascript', function(cm, vim, helpers) { helpers.doEx('s/\\(\\d+\\)/$$ $\' $` $& \\1/') eq('a $$ $\' $` $& 0 b', cm.getValue()); }, { value: 'a 0 b' }); +testVim('ex_substitute_empty_arguments', function(cm,vim,helpers) { + cm.setCursor(0, 0); + helpers.doEx('s/a/b'); + cm.setCursor(1, 0); + helpers.doEx('s'); + eq('b b\nb b', cm.getValue()); +}, {value: 'a a\na a'}); // More complex substitute tests that test both pcre and nopcre options. function testSubstitute(name, options) { From 9ebe69980acd82aa13590a8e1b9d1174ec3edce9 Mon Sep 17 00:00:00 2001 From: Peter Kroon Date: Fri, 14 Mar 2014 16:41:51 +0100 Subject: [PATCH 012/127] [LICENCE] use current year --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 442d11cdce..d21bbea5a6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (C) 2013 by Marijn Haverbeke and others +Copyright (C) 2014 by Marijn Haverbeke and others Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From dac3b43f7b85163a5b428ddb77405860a08d51f8 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 17 Mar 2014 11:49:11 +0100 Subject: [PATCH 013/127] [lint addons] Don't error on missing dependencies Closes #2376 --- addon/lint/css-lint.js | 1 + addon/lint/javascript-lint.js | 1 + 2 files changed, 2 insertions(+) diff --git a/addon/lint/css-lint.js b/addon/lint/css-lint.js index 1de71fbcbd..51567c11e0 100644 --- a/addon/lint/css-lint.js +++ b/addon/lint/css-lint.js @@ -4,6 +4,7 @@ CodeMirror.registerHelper("lint", "css", function(text) { var found = []; + if (!window.CSSLint) return found; var results = CSSLint.verify(text), messages = results.messages, message = null; for ( var i = 0; i < messages.length; i++) { message = messages[i]; diff --git a/addon/lint/javascript-lint.js b/addon/lint/javascript-lint.js index 7123ab7e64..73066fb3da 100644 --- a/addon/lint/javascript-lint.js +++ b/addon/lint/javascript-lint.js @@ -12,6 +12,7 @@ "Unclosed string", "Stopping, unable to continue" ]; function validator(text, options) { + if (!window.JSHINT) return []; JSHINT(text, options); var errors = JSHINT.data().errors, result = []; if (errors) parseErrors(errors, result); From d03267a340a7e1d01e5e75f5c7211c22bf647c0b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 17 Mar 2014 11:59:35 +0100 Subject: [PATCH 014/127] [xml mode] Fix indentation after 'context grabber' Closes #2374 --- mode/xml/test.js | 7 ++++++- mode/xml/xml.js | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/mode/xml/test.js b/mode/xml/test.js index e0dfde0f25..1b9d9d1760 100644 --- a/mode/xml/test.js +++ b/mode/xml/test.js @@ -24,7 +24,7 @@ "[tag&bracket ]"); // HTML tests - mode = CodeMirror.getMode({indentUnit: 2}, "text/html"); mname = "html"; + mode = CodeMirror.getMode({indentUnit: 2}, "text/html"); MT("selfclose", "[tag&bracket <][tag html][tag&bracket >]", @@ -40,4 +40,9 @@ MT("valueless", "[tag&bracket <][tag input] [attribute type]=[string checkbox] [attribute checked][tag&bracket />]"); + MT("pThenArticle", + "[tag&bracket <][tag p][tag&bracket >]", + " foo", + "[tag&bracket <][tag article][tag&bracket >]bar"); + })(); diff --git a/mode/xml/xml.js b/mode/xml/xml.js index 1fbbbddd72..c51b5ea596 100644 --- a/mode/xml/xml.js +++ b/mode/xml/xml.js @@ -337,8 +337,8 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { } } else if (tagAfter) { // Opening tag spotted while (context) { - var grabbers = Kludges.contextGrabbers[tagAfter[2]]; - if (grabbers && grabbers.hasOwnProperty(context.tagName)) + var grabbers = Kludges.contextGrabbers[context.tagName]; + if (grabbers && grabbers.hasOwnProperty(tagAfter[2])) context = context.prev; else break; From 362476cdeb3cc2ac6b805136cb5b746b1e57ac93 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 17 Mar 2014 12:11:19 +0100 Subject: [PATCH 015/127] [xml mode] Fix parsing of quote-less attribute values Issue #2373 --- 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 c51b5ea596..4253da9b63 100644 --- a/mode/xml/xml.js +++ b/mode/xml/xml.js @@ -117,7 +117,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { state.stringStartCol = stream.column(); return state.tokenize(stream, state); } else { - stream.eatWhile(/[^\s\u00a0=<>\"\'\/]/); + stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/); return "word"; } } From efc576b8418a35dccdc15e3d77c3b8b7f2ff8ed9 Mon Sep 17 00:00:00 2001 From: Peter Kroon Date: Sun, 16 Mar 2014 15:27:28 +0100 Subject: [PATCH 016/127] [bidi demo] Fix html highlighting in demo --- demo/bidi.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/bidi.html b/demo/bidi.html index 4f1f8f3e45..569693c875 100644 --- a/demo/bidi.html +++ b/demo/bidi.html @@ -46,7 +46,7 @@
    theme (string)
    موضوع لنمط المحرر مع. يجب عليك التأكد من الملف CSS تحديد المقابلة .cm-s-[name] يتم تحميل أنماط (انظر - theme الدليل في التوزيع). + theme الدليل في التوزيع). الافتراضي هو "default" ، والتي تم تضمينها في الألوان codemirror.css. فمن الممكن استخدام فئات متعددة في تطبيق السمات مرة واحدة على سبيل المثال "foo bar" From fe9a348ede5250be50f64ee08e0c2dd0ff685b54 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 17 Mar 2014 13:34:50 +0100 Subject: [PATCH 017/127] [css mode] Add nonStandardPropertyKeywords list And style them differently from unknown properties. Issue #2356 --- mode/css/css.js | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/mode/css/css.js b/mode/css/css.js index 6cc4b71b05..108ec8bc29 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -8,6 +8,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { mediaTypes = parserConfig.mediaTypes || {}, mediaFeatures = parserConfig.mediaFeatures || {}, propertyKeywords = parserConfig.propertyKeywords || {}, + nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {}, colorKeywords = parserConfig.colorKeywords || {}, valueKeywords = parserConfig.valueKeywords || {}, fontProperties = parserConfig.fontProperties || {}, @@ -162,9 +163,13 @@ CodeMirror.defineMode("css", function(config, parserConfig) { states.block = function(type, stream, state) { if (type == "word") { - if (propertyKeywords.hasOwnProperty(stream.current().toLowerCase())) { + var word = stream.current().toLowerCase(); + if (propertyKeywords.hasOwnProperty(word)) { override = "property"; return "maybeprop"; + } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) { + override = "string-2"; + return "maybeprop"; } else if (allowNested) { override = stream.match(/^\s*:/, false) ? "property" : "tag"; return "block"; @@ -437,7 +442,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "vertical-align", "visibility", "voice-balance", "voice-duration", "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress", "voice-volume", "volume", "white-space", "widows", "width", "word-break", - "word-spacing", "word-wrap", "z-index", "zoom", + "word-spacing", "word-wrap", "z-index", // SVG-specific "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color", "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events", @@ -450,6 +455,14 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "glyph-orientation-vertical", "kerning", "text-anchor", "writing-mode" ], propertyKeywords = keySet(propertyKeywords_); + var nonStandardPropertyKeywords = [ + "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color", + "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color", + "scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside", + "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button", + "searchfield-results-decoration", "zoom" + ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords); + var colorKeywords_ = [ "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", @@ -569,7 +582,8 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "font-stretch", "font-weight", "font-style" ], fontProperties = keySet(fontProperties_); - var allWords = mediaTypes_.concat(mediaFeatures_).concat(propertyKeywords_).concat(colorKeywords_).concat(valueKeywords_); + var allWords = mediaTypes_.concat(mediaFeatures_).concat(propertyKeywords_) + .concat(nonStandardPropertyKeywords).concat(colorKeywords_).concat(valueKeywords_); CodeMirror.registerHelper("hintWords", "css", allWords); function tokenCComment(stream, state) { @@ -598,6 +612,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { mediaTypes: mediaTypes, mediaFeatures: mediaFeatures, propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, colorKeywords: colorKeywords, valueKeywords: valueKeywords, fontProperties: fontProperties, @@ -620,6 +635,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { mediaTypes: mediaTypes, mediaFeatures: mediaFeatures, propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, colorKeywords: colorKeywords, valueKeywords: valueKeywords, fontProperties: fontProperties, @@ -660,6 +676,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { mediaTypes: mediaTypes, mediaFeatures: mediaFeatures, propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, colorKeywords: colorKeywords, valueKeywords: valueKeywords, fontProperties: fontProperties, From afcede21236076a91a5602490bf0a1345c4eed90 Mon Sep 17 00:00:00 2001 From: binny Date: Fri, 14 Mar 2014 03:21:43 +0530 Subject: [PATCH 018/127] [vim] Fix 'mark to move to first nonwhitespace --- keymap/vim.js | 7 ++++--- test/vim_test.js | 16 +++++++++------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index 899c6c0e83..732c9e4a03 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -194,7 +194,7 @@ { keys: [','], type: 'motion', motion: 'repeatLastCharacterSearch', motionArgs: { forward: false }}, { keys: ['\'', 'character'], type: 'motion', motion: 'goToMark', - motionArgs: {toJumplist: true}}, + motionArgs: {toJumplist: true, linewise: true}}, { keys: ['`', 'character'], type: 'motion', motion: 'goToMark', motionArgs: {toJumplist: true}}, { keys: [']', '`'], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true } }, @@ -1380,10 +1380,11 @@ highlightSearchMatches(cm, query); return findNext(cm, prev/** prev */, query, motionArgs.repeat); }, - goToMark: function(_cm, motionArgs, vim) { + goToMark: function(cm, motionArgs, vim) { var mark = vim.marks[motionArgs.selectedCharacter]; if (mark) { - return mark.find(); + var pos = mark.find(); + return motionArgs.linewise ? { line: pos.line, ch: findFirstNonWhiteSpaceCharacter(cm.getLine(pos.line)) } : pos; } return null; }, diff --git a/test/vim_test.js b/test/vim_test.js index 4d9525e15e..10eda070c6 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -258,7 +258,7 @@ testJumplist('jumplist_gg', ['g', 'g', ''], [5,2], [5,2]); testJumplist('jumplist_%', ['%', ''], [1,5], [1,5]); testJumplist('jumplist_{', ['{', ''], [1,5], [1,5]); testJumplist('jumplist_}', ['}', ''], [1,5], [1,5]); -testJumplist('jumplist_\'', ['m', 'a', 'h', '\'', 'a', 'h', ''], [1,5], [1,5]); +testJumplist('jumplist_\'', ['m', 'a', 'h', '\'', 'a', 'h', ''], [1,0], [1,5]); testJumplist('jumplist_`', ['m', 'a', 'h', '`', 'a', 'h', ''], [1,5], [1,5]); testJumplist('jumplist_*_cachedCursor', ['*', ''], [1,3], [1,3]); testJumplist('jumplist_#_cachedCursor', ['#', ''], [1,3], [1,3]); @@ -1265,11 +1265,13 @@ testVim('mark', function(cm, vim, helpers) { cm.setCursor(2, 2); helpers.doKeys('m', 't'); cm.setCursor(0, 0); - helpers.doKeys('\'', 't'); - helpers.assertCursorAt(2, 2); - cm.setCursor(0, 0); helpers.doKeys('`', 't'); helpers.assertCursorAt(2, 2); + cm.setCursor(2, 0); + cm.replaceRange(' h', cm.getCursor()); + cm.setCursor(0, 0); + helpers.doKeys('\'', 't'); + helpers.assertCursorAt(2, 3); }); testVim('jumpToMark_next', function(cm, vim, helpers) { cm.setCursor(2, 2); @@ -1519,13 +1521,13 @@ testVim('visual_line', function(cm, vim, helpers) { eq(' 4\n 5', cm.getValue()); }, { value: ' 1\n 2\n 3\n 4\n 5' }); testVim('visual_marks', function(cm, vim, helpers) { - helpers.doKeys('l', 'v', 'l', 'l', 'v'); + helpers.doKeys('l', 'v', 'l', 'l', 'j', 'j', 'v'); // Test visual mode marks - cm.setCursor(0, 0); + cm.setCursor(2, 1); helpers.doKeys('\'', '<'); helpers.assertCursorAt(0, 1); helpers.doKeys('\'', '>'); - helpers.assertCursorAt(0, 3); + helpers.assertCursorAt(2, 0); }); testVim('visual_join', function(cm, vim, helpers) { helpers.doKeys('l', 'V', 'l', 'j', 'j', 'J'); From 0afc1a55e72adf5d2945c9bf2549683b567424b6 Mon Sep 17 00:00:00 2001 From: binny Date: Sun, 16 Mar 2014 21:38:10 +0530 Subject: [PATCH 019/127] [vim] Implement gstar and ghash --- keymap/vim.js | 11 +++++++---- test/vim_test.js | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index 732c9e4a03..7e7accb608 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -322,9 +322,11 @@ { keys: ['?'], type: 'search', searchArgs: { forward: false, querySrc: 'prompt', toJumplist: true }}, { keys: ['*'], type: 'search', - searchArgs: { forward: true, querySrc: 'wordUnderCursor', toJumplist: true }}, + searchArgs: { forward: true, querySrc: 'wordUnderCursor', wholeWordOnly: true, toJumplist: true }}, { keys: ['#'], type: 'search', - searchArgs: { forward: false, querySrc: 'wordUnderCursor', toJumplist: true }}, + searchArgs: { forward: false, querySrc: 'wordUnderCursor', wholeWordOnly: true, toJumplist: true }}, + { keys: ['g', '*'], type: 'search', searchArgs: { forward: true, querySrc: 'wordUnderCursor', toJumplist: true }}, + { keys: ['g', '#'], type: 'search', searchArgs: { forward: false, querySrc: 'wordUnderCursor', toJumplist: true }}, // Ex command { keys: [':'], type: 'ex' } ]; @@ -1054,6 +1056,7 @@ return; } var forward = command.searchArgs.forward; + var wholeWordOnly = command.searchArgs.wholeWordOnly; getSearchState(cm).setReversed(!forward); var promptPrefix = (forward) ? '/' : '?'; var originalQuery = getSearchState(cm).getQuery(); @@ -1138,8 +1141,8 @@ } var query = cm.getLine(word.start.line).substring(word.start.ch, word.end.ch); - if (isKeyword) { - query = '\\b' + query + '\\b'; + if (isKeyword && wholeWordOnly) { + query = '\\b' + query + '\\b'; } else { query = escapeRegex(query); } diff --git a/test/vim_test.js b/test/vim_test.js index 10eda070c6..7393abfea6 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -1747,6 +1747,22 @@ testVim('#', function(cm, vim, helpers) { helpers.doKeys('#'); helpers.assertCursorAt(1, 8); }, { value: ' := match nomatch match \nnomatch Match' }); +testVim('g*', function(cm, vim, helpers) { + cm.setCursor(0, 8); + helpers.doKeys('g', '*'); + helpers.assertCursorAt(0, 18); + cm.setCursor(0, 8); + helpers.doKeys('3', 'g', '*'); + helpers.assertCursorAt(1, 8); +}, { value: 'matches match alsoMatch\nmatchme matching' }); +testVim('g#', function(cm, vim, helpers) { + cm.setCursor(0, 8); + helpers.doKeys('g', '#'); + helpers.assertCursorAt(0, 0); + cm.setCursor(0, 8); + helpers.doKeys('3', 'g', '#'); + helpers.assertCursorAt(1, 0); +}, { value: 'matches match alsoMatch\nmatchme matching' }); testVim('macro_insert', function(cm, vim, helpers) { cm.setCursor(0, 0); helpers.doKeys('q', 'a', '0', 'i'); From ef1b02eb1f2f0abef019eda80b04a752fd777c20 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 18 Mar 2014 09:39:12 +0100 Subject: [PATCH 020/127] Remove fakedLastChar hack Issue #1474 was the cause of this hack Issue #2384 was apparently caused by it Recent Webkit-ish browsers seem to no longer have the problem that it was working around. --- lib/codemirror.js | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index ee1e418b65..e106648583 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1508,10 +1508,6 @@ window.CodeMirror = (function() { function readInput(cm) { var input = cm.display.input, prevInput = cm.display.prevInput, doc = cm.doc, sel = doc.sel; if (!cm.state.focused || hasSelection(input) || isReadOnly(cm) || cm.options.disableInput) return false; - 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 (text == prevInput && posEq(sel.from, sel.to)) return false; if (ie && !ie_lt9 && cm.display.inputHasSelection === text) { @@ -1678,16 +1674,6 @@ window.CodeMirror = (function() { 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 fbf533cf31bc9391a7862f28ea0d6109adc4b415 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Mon, 17 Mar 2014 16:48:16 +0100 Subject: [PATCH 021/127] [solarized theme] Remove shadow, conform to other solarized themes --- theme/solarized.css | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/theme/solarized.css b/theme/solarized.css index 9c2e914833..c9c84097d0 100644 --- a/theme/solarized.css +++ b/theme/solarized.css @@ -121,8 +121,6 @@ http://ethanschoonover.com/solarized/img/solarized-palette.png /* Gutter border and some shadow from it */ .cm-s-solarized .CodeMirror-gutters { - padding: 0 15px 0 10px; - box-shadow: 0 10px 20px black; border-right: 1px solid; } @@ -130,7 +128,7 @@ http://ethanschoonover.com/solarized/img/solarized-palette.png /* Dark */ .cm-s-solarized.cm-s-dark .CodeMirror-gutters { - background-color: #073642; + background-color: #002b36; border-color: #00232c; } @@ -140,23 +138,20 @@ http://ethanschoonover.com/solarized/img/solarized-palette.png /* Light */ .cm-s-solarized.cm-s-light .CodeMirror-gutters { - background-color: #eee8d5; + background-color: #fdf6e3; border-color: #eee8d5; } /* Common */ .cm-s-solarized .CodeMirror-linenumber { color: #586e75; + padding: 0 5px; } .cm-s-solarized .CodeMirror-gutter .CodeMirror-gutter-text { color: #586e75; } -.cm-s-solarized .CodeMirror-lines { - padding-left: 5px; -} - .cm-s-solarized .CodeMirror-lines .CodeMirror-cursor { border-left: 1px solid #819090; } @@ -171,11 +166,3 @@ view-port .cm-s-solarized.cm-s-light .CodeMirror-activeline-background { background: rgba(0, 0, 0, 0.10); } - -/* -View-port and gutter both get little noise background to give it a real feel. -*/ -.cm-s-solarized.CodeMirror, -.cm-s-solarized .CodeMirror-gutters { - background-image: url("data:image/png;base64,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"); -} From 7c134914ecbe9d4236cdcd25ab3b11278bf05f3a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 18 Mar 2014 10:00:50 +0100 Subject: [PATCH 022/127] [javascript mode] Fix parsing of ops and derefs after function literal Closes #2381 --- mode/javascript/javascript.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 37f48cbfae..64a6bf0040 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -345,7 +345,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma; if (atomicTypes.hasOwnProperty(type)) return cont(maybeop); - if (type == "function") return cont(functiondef); + if (type == "function") return cont(functiondef, maybeop); if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression); if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop); if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression); From 01e7ab9ce94bbc97328f76c0325bdfe99ed66000 Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Tue, 18 Mar 2014 20:47:36 +0100 Subject: [PATCH 023/127] [vim] Update documentation to set vimMode instead of keyMap --- demo/vim.html | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/demo/vim.html b/demo/vim.html index 379fac1475..f7445ed6c6 100644 --- a/demo/vim.html +++ b/demo/vim.html @@ -51,9 +51,10 @@

    The vim keybindings are enabled by including keymap/vim.js and setting -the keyMap option to "vim". Because -CodeMirror's internal API is quite different from Vim, they are only -a loose approximation of actual vim bindings, though.

    +the vimMode option to true. This will also +automatically change the keyMap option to "vim". +Because CodeMirror's internal API is quite different from Vim, they are only a +loose approximation of actual vim bindings, though.

    DOWNLOAD LATEST RELEASE -
    version 3.22 (Release notes)
    +
    version 3.23 (Release notes)
    DONATE WITH PAYPAL diff --git a/lib/codemirror.js b/lib/codemirror.js index 0b3c231d3e..6f08c9871e 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -6089,7 +6089,7 @@ window.CodeMirror = (function() { // THE END - CodeMirror.version = "3.22.1"; + CodeMirror.version = "3.23.0"; return CodeMirror; })(); diff --git a/package.json b/package.json index 4209057376..734ddbfae5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version":"3.22.1", + "version":"3.23.0", "main": "lib/codemirror.js", "description": "In-browser code editing made bearable", "licenses": [{"type": "MIT", From 8d87f56b80810e150aa604522dcde25d0e749d02 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 20 Mar 2014 11:24:07 +0100 Subject: [PATCH 030/127] Bump version number post-3.23 --- 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 e5cb6363a3..516ace716a 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -59,7 +59,7 @@

    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 -[![Build Status](https://secure.travis-ci.org/marijnh/CodeMirror.png?branch=master)](http://travis-ci.org/marijnh/CodeMirror) -[![NPM version](https://badge.fury.io/js/codemirror.png)](http://badge.fury.io/js/codemirror) +[![Build Status](https://travis-ci.org/marijnh/CodeMirror.svg)](https://travis-ci.org/marijnh/CodeMirror) +[![NPM version](https://img.shields.io/npm/v/codemirror.svg)](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(""); 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 + - +
    -

    Verilog mode

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

    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

    DOWNLOAD LATEST RELEASE -
    version 4.0 (Release notes)
    +
    version 4.1 (Release notes)
    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",