diff --git a/AUTHORS b/AUTHORS index acc10fe16d..362fd94a7e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -33,6 +33,7 @@ Anders Nawroth Anderson Mesquita Andreas Reischuck Andre von Houck +Andrey Fedorov Andrey Lushnikov Andy Joslin Andy Kimball @@ -84,6 +85,7 @@ dagsta daines Dan Heberden Daniel, Dao Quang Minh +Daniele Di Sarli Daniel Faust Daniel Huigens Daniel KJ @@ -145,6 +147,7 @@ Hakan Tunc Hans Engel Hardest Hasan Karahan +Hiroyuki Makino hitsthings Hocdoc Ian Beck @@ -215,6 +218,7 @@ Leonid Khachaturov Leonya Khachaturov Liam Newman LM +lochel Lorenzo Stoakes Luciano Longo lynschinzer @@ -223,6 +227,7 @@ Maksym Taran Malay Majithia Manuel Rego Casasnovas Marat Dreizin +Marcel Gerber Marco Aurélio Marco Munizaga Marcus Bointon @@ -316,6 +321,7 @@ Sascha Peilicke satchmorun sathyamoorthi SCLINIC\jdecker +Scott Aikin Sebastian Zaha shaund shaun gilchrist @@ -324,6 +330,7 @@ sheopory Shiv Deepak Shmuel Englard Shubham Jain +snasa soliton4 sonson spastorelli diff --git a/addon/dialog/dialog.js b/addon/dialog/dialog.js index 946040cb91..35a6103c2d 100644 --- a/addon/dialog/dialog.js +++ b/addon/dialog/dialog.js @@ -129,8 +129,8 @@ CodeMirror.defineExtension("openNotification", function(template, options) { closeNotification(this, close); var dialog = dialogDiv(this, template, options && options.bottom); - var duration = options && (options.duration === undefined ? 5000 : options.duration); var closed = false, doneTimer; + var duration = options && typeof options.duration !== "undefined" ? options.duration : 5000; function close() { if (closed) return; @@ -143,7 +143,10 @@ CodeMirror.e_preventDefault(e); close(); }); + if (duration) - doneTimer = setTimeout(close, options.duration); + doneTimer = setTimeout(close, duration); + + return close; }); }); diff --git a/addon/edit/closetag.js b/addon/edit/closetag.js index 69ea4446be..a0bec7dd43 100644 --- a/addon/edit/closetag.js +++ b/addon/edit/closetag.js @@ -102,11 +102,25 @@ var pos = ranges[i].head, tok = cm.getTokenAt(pos); var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; if (tok.type == "string" || tok.string.charAt(0) != "<" || - tok.start != pos.ch - 1 || inner.mode.name != "xml" || - !state.context || !state.context.tagName || - closingTagExists(cm, state.context.tagName, pos, state)) + tok.start != pos.ch - 1) return CodeMirror.Pass; - replacements[i] = "/" + state.context.tagName + ">"; + // Kludge to get around the fact that we are not in XML mode + // when completing in JS/CSS snippet in htmlmixed mode. Does not + // work for other XML embedded languages (there is no general + // way to go from a mixed mode to its current XML state). + if (inner.mode.name != "xml") { + if (cm.getMode().name == "htmlmixed" && inner.mode.name == "javascript") + replacements[i] = "/script>"; + else if (cm.getMode().name == "htmlmixed" && inner.mode.name == "css") + replacements[i] = "/style>"; + else + return CodeMirror.Pass; + } else { + if (!state.context || !state.context.tagName || + closingTagExists(cm, state.context.tagName, pos, state)) + return CodeMirror.Pass; + replacements[i] = "/" + state.context.tagName + ">"; + } } cm.replaceSelections(replacements); ranges = cm.listSelections(); diff --git a/addon/hint/html-hint.js b/addon/hint/html-hint.js index addd9b7bc0..992218f288 100755 --- a/addon/hint/html-hint.js +++ b/addon/hint/html-hint.js @@ -3,9 +3,9 @@ (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS - mod(require("../../lib/codemirror")); + mod(require("../../lib/codemirror", "./xml-hint")); else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); + define(["../../lib/codemirror", "./xml-hint"], mod); else // Plain browser env mod(CodeMirror); })(function(CodeMirror) { diff --git a/addon/hint/show-hint.css b/addon/hint/show-hint.css index 8a4ff052e3..924e638f7f 100644 --- a/addon/hint/show-hint.css +++ b/addon/hint/show-hint.css @@ -32,7 +32,7 @@ cursor: pointer; } -.CodeMirror-hint-active { +li.CodeMirror-hint-active { background: #08f; color: white; } diff --git a/addon/merge/merge.js b/addon/merge/merge.js index d9b277664b..da3ea47ccf 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -1,17 +1,17 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: http://codemirror.net/LICENSE +// declare global: diff_match_patch, DIFF_INSERT, DIFF_DELETE, DIFF_EQUAL + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS - mod(require("../../lib/codemirror")); + mod(require("../../lib/codemirror"), require("diff_match_patch")); else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); + define(["../../lib/codemirror", "diff_match_patch"], mod); else // Plain browser env - mod(CodeMirror); -})(function(CodeMirror) { + mod(CodeMirror, diff_match_patch); +})(function(CodeMirror, diff_match_patch) { "use strict"; - // declare global: diff_match_patch, DIFF_INSERT, DIFF_DELETE, DIFF_EQUAL - var Pos = CodeMirror.Pos; var svgNS = "http://www.w3.org/2000/svg"; diff --git a/addon/search/match-highlighter.js b/addon/search/match-highlighter.js index 14dd4d4184..e9a22721f7 100644 --- a/addon/search/match-highlighter.js +++ b/addon/search/match-highlighter.js @@ -8,12 +8,15 @@ // document. // // The option can be set to true to simply enable it, or to a -// {minChars, style, showToken} object to explicitly configure it. -// minChars is the minimum amount of characters that should be +// {minChars, style, wordsOnly, showToken, delay} object to explicitly +// configure it. minChars is the minimum amount of characters that should be // selected for the behavior to occur, and style is the token style to // apply to the matches. This will be prefixed by "cm-" to create an -// actual CSS class name. showToken, when enabled, will cause the -// current token to be highlighted when nothing is selected. +// actual CSS class name. If wordsOnly is enabled, the matches will be +// highlighted only if the selected text is a word. showToken, when enabled, +// will cause the current token to be highlighted when nothing is selected. +// delay is used to specify how much time to wait, in milliseconds, before +// highlighting the matches. (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS @@ -28,6 +31,7 @@ var DEFAULT_MIN_CHARS = 2; var DEFAULT_TOKEN_STYLE = "matchhighlight"; var DEFAULT_DELAY = 100; + var DEFAULT_WORDS_ONLY = false; function State(options) { if (typeof options == "object") { @@ -35,10 +39,12 @@ this.style = options.style; this.showToken = options.showToken; this.delay = options.delay; + this.wordsOnly = options.wordsOnly; } if (this.style == null) this.style = DEFAULT_TOKEN_STYLE; if (this.minChars == null) this.minChars = DEFAULT_MIN_CHARS; if (this.delay == null) this.delay = DEFAULT_DELAY; + if (this.wordsOnly == null) this.wordsOnly = DEFAULT_WORDS_ONLY; this.overlay = this.timeout = null; } @@ -81,12 +87,30 @@ } var from = cm.getCursor("from"), to = cm.getCursor("to"); if (from.line != to.line) return; + if (state.wordsOnly && !isWord(cm, from, to)) return; var selection = cm.getRange(from, to).replace(/^\s+|\s+$/g, ""); if (selection.length >= state.minChars) cm.addOverlay(state.overlay = makeOverlay(selection, false, state.style)); }); } + function isWord(cm, from, to) { + var str = cm.getRange(from, to); + if (str.match(/^\w+$/) !== null) { + if (from.ch > 0) { + var pos = {line: from.line, ch: from.ch - 1}; + var chr = cm.getRange(pos, from); + if (chr.match(/\W/) === null) return false; + } + if (to.ch < cm.getLine(from.line).length) { + var pos = {line: to.line, ch: to.ch + 1}; + var chr = cm.getRange(to, pos); + if (chr.match(/\W/) === null) return false; + } + return true; + } else return false; + } + function boundariesAround(stream, re) { return (!stream.start || !re.test(stream.string.charAt(stream.start - 1))) && (stream.pos == stream.string.length || !re.test(stream.string.charAt(stream.pos))); diff --git a/bower.json b/bower.json index 9cf2abecfe..638b9d0016 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version":"4.5.0", + "version":"4.6.0", "main": ["lib/codemirror.js", "lib/codemirror.css"], "ignore": [ "**/.*", diff --git a/demo/markselection.html b/demo/markselection.html index 93e38ec833..d729515e58 100644 --- a/demo/markselection.html +++ b/demo/markselection.html @@ -12,6 +12,7 @@ .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;} .CodeMirror-selected { background-color: blue !important; } .CodeMirror-selectedtext { color: white; } + .styled-background { background-color: #ff7; } + + + +

Simple mode that tries to handle Modelica as well as it can.

+ +

MIME types defined: text/x-modelica + (Modlica code).

+ diff --git a/mode/modelica/modelica.js b/mode/modelica/modelica.js new file mode 100644 index 0000000000..77ec7a3c18 --- /dev/null +++ b/mode/modelica/modelica.js @@ -0,0 +1,245 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Modelica support for CodeMirror, copyright (c) by Lennart Ochel + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +}) + +(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("modelica", function(config, parserConfig) { + + var indentUnit = config.indentUnit; + var keywords = parserConfig.keywords || {}; + var builtin = parserConfig.builtin || {}; + var atoms = parserConfig.atoms || {}; + + var isSingleOperatorChar = /[;=\(:\),{}.*<>+\-\/^\[\]]/; + var isDoubleOperatorChar = /(:=|<=|>=|==|<>|\.\+|\.\-|\.\*|\.\/|\.\^)/; + var isDigit = /[0-9]/; + var isNonDigit = /[_a-zA-Z]/; + + function tokenLineComment(stream, state) { + stream.skipToEnd(); + state.tokenize = null; + return "comment"; + } + + function tokenBlockComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (maybeEnd && ch == "/") { + state.tokenize = null; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function tokenString(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == '"' && !escaped) { + state.tokenize = null; + state.sol = false; + break; + } + escaped = !escaped && ch == "\\"; + } + + return "string"; + } + + function tokenIdent(stream, state) { + stream.eatWhile(isDigit); + while (stream.eat(isDigit) || stream.eat(isNonDigit)) { } + + + var cur = stream.current(); + + if(state.sol && (cur == "package" || cur == "model" || cur == "when" || cur == "connector")) state.level++; + else if(state.sol && cur == "end" && state.level > 0) state.level--; + + state.tokenize = null; + state.sol = false; + + if (keywords.propertyIsEnumerable(cur)) return "keyword"; + else if (builtin.propertyIsEnumerable(cur)) return "builtin"; + else if (atoms.propertyIsEnumerable(cur)) return "atom"; + else return "variable"; + } + + function tokenQIdent(stream, state) { + while (stream.eat(/[^']/)) { } + + state.tokenize = null; + state.sol = false; + + if(stream.eat("'")) + return "variable"; + else + return "error"; + } + + function tokenUnsignedNuber(stream, state) { + stream.eatWhile(isDigit); + if (stream.eat('.')) { + stream.eatWhile(isDigit); + } + if (stream.eat('e') || stream.eat('E')) { + if (!stream.eat('-')) + stream.eat('+'); + stream.eatWhile(isDigit); + } + + state.tokenize = null; + state.sol = false; + return "number"; + } + + // Interface + return { + startState: function() { + return { + tokenize: null, + level: 0, + sol: true + }; + }, + + token: function(stream, state) { + if(state.tokenize != null) { + return state.tokenize(stream, state); + } + + if(stream.sol()) { + state.sol = true; + } + + // WHITESPACE + if(stream.eatSpace()) { + state.tokenize = null; + return null; + } + + var ch = stream.next(); + + // LINECOMMENT + if(ch == '/' && stream.eat('/')) { + state.tokenize = tokenLineComment; + } + // BLOCKCOMMENT + else if(ch == '/' && stream.eat('*')) { + state.tokenize = tokenBlockComment; + } + // TWO SYMBOL TOKENS + else if(isDoubleOperatorChar.test(ch+stream.peek())) { + stream.next(); + state.tokenize = null; + return "operator"; + } + // SINGLE SYMBOL TOKENS + else if(isSingleOperatorChar.test(ch)) { + state.tokenize = null; + return "operator"; + } + // IDENT + else if(isNonDigit.test(ch)) { + state.tokenize = tokenIdent; + } + // Q-IDENT + else if(ch == "'" && stream.peek() && stream.peek() != "'") { + state.tokenize = tokenQIdent; + } + // STRING + else if(ch == '"') { + state.tokenize = tokenString; + } + // UNSIGNED_NUBER + else if(isDigit.test(ch)) { + state.tokenize = tokenUnsignedNuber; + } + // ERROR + else { + state.tokenize = null; + return "error"; + } + + return state.tokenize(stream, state); + }, + + indent: function(state, textAfter) { + if (state.tokenize != null) return CodeMirror.Pass; + + var level = state.level; + if(/(algorithm)/.test(textAfter)) level--; + if(/(equation)/.test(textAfter)) level--; + if(/(initial algorithm)/.test(textAfter)) level--; + if(/(initial equation)/.test(textAfter)) level--; + if(/(end)/.test(textAfter)) level--; + + if(level > 0) + return indentUnit*level; + else + return 0; + }, + + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//" + }; + }); + + function words(str) { + var obj = {}, words = str.split(" "); + for (var i=0; i]/); + stream.eatWhile(/[^\s>]/); stream.next(); } token.name = 'string-2'; diff --git a/mode/xml/xml.js b/mode/xml/xml.js index 786507d2e4..2f3b8f87a0 100644 --- a/mode/xml/xml.js +++ b/mode/xml/xml.js @@ -21,7 +21,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true, 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true, 'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true, - 'track': true, 'wbr': true}, + 'track': true, 'wbr': true, 'menuitem': true}, implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true, 'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true, 'th': true, 'tr': true}, diff --git a/package.json b/package.json index 47f05587aa..924c076f2c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version":"4.5.0", + "version":"4.6.0", "main": "lib/codemirror.js", "description": "In-browser code editing made bearable", "licenses": [{"type": "MIT", diff --git a/theme/mbo.css b/theme/mbo.css index 6cb2b18d9b..0ad6360b50 100644 --- a/theme/mbo.css +++ b/theme/mbo.css @@ -1,6 +1,10 @@ -/* Based on mbonaci's Brackets mbo theme */ +/****************************************************************/ +/* Based on mbonaci's Brackets mbo theme */ +/* https://github.com/mbonaci/global/blob/master/Mbo.tmTheme */ +/* Create your own: http://tmtheme-editor.herokuapp.com */ +/****************************************************************/ -.cm-s-mbo.CodeMirror {background: #2c2c2c; color: #ffffe9;} +.cm-s-mbo.CodeMirror {background: #2c2c2c; color: #ffffec;} .cm-s-mbo div.CodeMirror-selected {background: #716C62 !important;} .cm-s-mbo .CodeMirror-gutters {background: #4e4e4e; border-right: 0px;} .cm-s-mbo .CodeMirror-guttermarker { color: white; } @@ -15,6 +19,7 @@ .cm-s-mbo span.cm-property, .cm-s-mbo span.cm-attribute {color: #9ddfe9;} .cm-s-mbo span.cm-keyword {color: #ffb928;} .cm-s-mbo span.cm-string {color: #ffcf6c;} +.cm-s-mbo span.cm-string.cm-property {color: #ffffec;} .cm-s-mbo span.cm-variable {color: #ffffec;} .cm-s-mbo span.cm-variable-2 {color: #00a8c6;} @@ -23,17 +28,8 @@ .cm-s-mbo span.cm-tag {color: #9ddfe9;} .cm-s-mbo span.cm-link {color: #f54b07;} .cm-s-mbo span.cm-error {border-bottom: #636363; color: #ffffec;} +.cm-s-mbo span.cm-qualifier {color: #ffffec;} .cm-s-mbo .CodeMirror-activeline-background {background: #494b41 !important;} -.cm-s-mbo .CodeMirror-matchingbracket { - text-decoration: underline; - color: #f5e107 !important; - } - -.cm-s-mbo .CodeMirror-matchingtag { background: rgba(255, 255, 255, .37); } - -.cm-s-mbo span.cm-searching { - background-color: none; - background: none; - box-shadow: 0 0 0 1px #ffffec; -} +.cm-s-mbo .CodeMirror-matchingbracket {color: #222 !important;} +.cm-s-mbo .CodeMirror-matchingtag {background: rgba(255, 255, 255, .37);}