'Codemirror Auto Format after setValue
I'm using Codemirror for my app.
I noticed if I select all the text and press SHIFT+Tab it will auto align my code making it easier to read.
Here's an example of what my app currently renders:
<ul>
<li>
<font color="#f90000">
Apples
</font>
</li>
<li>
<font color="#ff9a3d">
Oranges
</font>
</li>
</ul>
Here's what I'm trying to get it to render:
<ul>
<li>
<font color="#f90000">
Apples
</font>
</li>
<li>
<font color="#ff9a3d">
Oranges
</font>
</li>
</ul>
Edit
Does anyone know if there's a way to do this without selecting the whole code manually in Codemirror?
Why? I have Codemirror running in my background of my app all code that's added is added dynamically, but when I save the final code it looks like above.
Solution 1:[1]
Ever since Codemirror has removed support for autoFormatRange() it's not worth the trouble to use it for formatting text. I use js-beautify instead.
var beautify_js = require('js-beautify').js_beautify
var beautify_html = require('js-beautify').html
var formattedJSON = beautify_js(jsonText, { indent_size: 2 });
var formattedXML = beautify_html(xmlText, { indent_size: 2 });
Solution 2:[2]
You can use the following code to achieve what you want :
function format() {
var totalLines = editor.lineCount();
editor.autoFormatRange({line:0, ch:0}, {line:totalLines});
}
Bind this function with your events, and it will auto-format the code.
Solution 3:[3]
By using codemirror formatting add-on you can achieve your requirement
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
mode: "htmlmixed",
extraKeys:{"Shift-Tab":autoFormatSelection}
});
function getSelectedRange() {
return { from: editor.getCursor(true), to: editor.getCursor(false) };
}
function autoFormatSelection() {
var range = getSelectedRange();
editor.autoFormatRange(range.from, range.to);
}
Source Link
Solution 4:[4]
Here is the original addon including a small update to let it work with CodeMirror V3 :
CodeMirror.extendMode("css", {
commentStart: "/*",
commentEnd: "*/",
newlineAfterToken: function(type, content) {
return /^[;{}]$/.test(content);
}
});
CodeMirror.extendMode("javascript", {
commentStart: "/*",
commentEnd: "*/",
newlineAfterToken: function(type, content, textAfter, state) {
if (this.jsonMode) {
return /^[\[,{]$/.test(content) || /^}/.test(textAfter);
} else {
if (content == ";" && state.lexical && state.lexical.type == ")") return false;
return /^[;{}]$/.test(content) && !/^;/.test(textAfter);
}
}
});
CodeMirror.extendMode("xml", {
commentStart: "<!--",
commentEnd: "-->",
newlineAfterToken: function(type, content, textAfter) {
return ( type == "tag" && />$/.test(content) || /^</.test(textAfter) ) || ( type == "tag bracket" && />$/.test(content) );
}
});
CodeMirror.defineExtension("commentRange", function (isComment, from, to) {
var cm = this, curMode = CodeMirror.innerMode(cm.getMode(), cm.getTokenAt(from).state).mode;
cm.operation(function() {
if (isComment) { // Comment range
cm.replaceRange(curMode.commentEnd, to);
cm.replaceRange(curMode.commentStart, from);
if (from.line == to.line && from.ch == to.ch) // An empty comment inserted - put cursor inside
cm.setCursor(from.line, from.ch + curMode.commentStart.length);
} else { // Uncomment range
var selText = cm.getRange(from, to);
var startIndex = selText.indexOf(curMode.commentStart);
var endIndex = selText.lastIndexOf(curMode.commentEnd);
if (startIndex > -1 && endIndex > -1 && endIndex > startIndex) {
// Take string till comment start
selText = selText.substr(0, startIndex)
// From comment start till comment end
+ selText.substring(startIndex + curMode.commentStart.length, endIndex)
// From comment end till string end
+ selText.substr(endIndex + curMode.commentEnd.length);
}
cm.replaceRange(selText, from, to);
}
});
});
CodeMirror.defineExtension("autoIndentRange", function (from, to) {
var cmInstance = this;
this.operation(function () {
for (var i = from.line; i <= to.line; i++) {
cmInstance.indentLine(i, "smart");
}
});
});
CodeMirror.defineExtension("autoFormatRange", function (from, to) {
var cm = this;
var outer = cm.getMode(), text = cm.getRange(from, to).split("\n");
var state = CodeMirror.copyState(outer, cm.getTokenAt(from).state);
var tabSize = cm.getOption("tabSize");
var out = "", lines = 0, atSol = from.ch == 0;
function newline() {
out += "\n";
atSol = true;
++lines;
}
for (var i = 0; i < text.length; ++i) {
var stream = new CodeMirror.StringStream(text[i], tabSize);
while (!stream.eol()) {
var inner = CodeMirror.innerMode(outer, state);
var style = outer.token(stream, state), cur = stream.current();
stream.start = stream.pos;
if (!atSol || /\S/.test(cur)) {
out += cur;
atSol = false;
}
if (!atSol && inner.mode.newlineAfterToken &&
inner.mode.newlineAfterToken(style, cur, stream.string.slice(stream.pos) || text[i+1] || "", inner.state))
newline();
}
if (!stream.pos && outer.blankLine) outer.blankLine(state);
if (!atSol)newline();
}
cm.operation(function () {
cm.replaceRange(out, from, to);
for (var cur = from.line + 1, end = from.line + lines; cur <= end; ++cur)
cm.indentLine(cur, "smart");
cm.setSelection(from, cm.getCursor(false));
});
});
Solution 5:[5]
A bit late, but maybe this can help someone who faces the same issue
autoFormatRange is not available anymore, however it is possible to indent the editor's value line by line, and no need to select the content
editor.eachLine(line => {
editor.indentLine(editor.getLineNumber(line), "smart");
})
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | RajV |
| Solution 2 | djadmin |
| Solution 3 | |
| Solution 4 | iole |
| Solution 5 | Alaa Eddine Cherbib |
