Skip to content
This repository was archived by the owner on Dec 14, 2023. It is now read-only.

Commit 76d5b24

Browse files
author
mattpass
committed
Prettier replace ranges, fix +input, 2 new cursor to num functions
1 parent bedf482 commit 76d5b24

File tree

1 file changed

+112
-20
lines changed

1 file changed

+112
-20
lines changed

assets/js/icecoder.js

Lines changed: 112 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ var ICEcoder = {
449449
thisCM.getLine(thisCMPrevLine) &&
450450
thisCM.getLine(thisCMPrevLine).length > 0 &&
451451
thisCM.getLine(thisCMPrevLine).replace(/\s/g, '').length === 0) {
452-
thisCM.replaceRange("", {line: thisCMPrevLine, ch: 0}, {line: thisCMPrevLine, ch: 1000000});
452+
thisCM.replaceRange("", {line: thisCMPrevLine, ch: 0}, {line: thisCMPrevLine, ch: 1000000}, "+input");
453453
}
454454

455455
// Set the cursor to text height, not line height
@@ -565,7 +565,7 @@ var ICEcoder = {
565565

566566
// Replace our string over the range, if this token string isn't blank and the end tag matches our original tag
567567
if ("" !== theTag.trim() && "undefined" !== typeof repl1 && "undefined" !== typeof repl2 && thisCM.getRange(repl1,repl2) === rData[0]) {
568-
thisCM.replaceRange(theTag, repl1, repl2);
568+
thisCM.replaceRange(theTag, repl1, repl2, "+input");
569569
// If at the close tag, don't autocomplete
570570
if (tagInfo.at === "close") {
571571
this.autocompleteSkip = true;
@@ -1110,16 +1110,16 @@ var ICEcoder = {
11101110
// Move lines in turn up
11111111
if ("up" === dir) {
11121112
for (let i = lineStart.line; i <= lineEnd.line; i++) {
1113-
thisCM.replaceRange(thisCM.getLine(i), {line: i - 1, ch: 0}, {line: i - 1, ch: 1000000});
1113+
thisCM.replaceRange(thisCM.getLine(i), {line: i - 1, ch: 0}, {line: i - 1, ch: 1000000}, "+input");
11141114
}
11151115
// ...or down
11161116
} else {
11171117
for (let i = lineEnd.line; i >= lineStart.line; i--) {
1118-
thisCM.replaceRange(thisCM.getLine(i), {line: i + 1, ch: 0}, {line: i + 1, ch: 1000000});
1118+
thisCM.replaceRange(thisCM.getLine(i), {line: i + 1, ch: 0}, {line: i + 1, ch: 1000000}, "+input");
11191119
}
11201120
}
11211121
// Now swap our final line with the swap line to complete the move
1122-
thisCM.replaceRange(swapLine, {line: "up" === dir ? lineEnd.line : lineStart.line, ch: 0}, {line: "up" === dir ? lineEnd.line : lineStart.line, ch: 1000000});
1122+
thisCM.replaceRange(swapLine, {line: "up" === dir ? lineEnd.line : lineStart.line, ch: 0}, {line: "up" === dir ? lineEnd.line : lineStart.line, ch: 1000000}, "+input");
11231123
// Finally set the moved selection
11241124
thisCM.setSelection(
11251125
{line: lineStart.line + ("up" === dir ? -1 : 1), ch: lineStart.ch},
@@ -1243,7 +1243,7 @@ var ICEcoder = {
12431243
thisCM = this.getThisCM();
12441244

12451245
if (!line) {line = thisCM.getCursor().line}
1246-
thisCM.replaceRange(thisCM.getLine(line) + "<br>", {line: line, ch: 0}, {line : line, ch: 1000000});
1246+
thisCM.replaceRange(thisCM.getLine(line) + "<br>", {line: line, ch: 0}, {line : line, ch: 1000000}, "+input");
12471247
},
12481248

12491249
// Insert a line before and auto-indent
@@ -1254,7 +1254,7 @@ var ICEcoder = {
12541254

12551255
if (!line) {line = thisCM.getCursor().line}
12561256
thisCM.operation(function() {
1257-
thisCM.replaceRange("\n" + thisCM.getLine(line), {line: line, ch: 0}, {line: line, ch: 1000000});
1257+
thisCM.replaceRange("\n" + thisCM.getLine(line), {line: line, ch: 0}, {line: line, ch: 1000000}, "+input");
12581258
thisCM.setCursor({line: thisCM.getCursor().line - 1, ch: 0});
12591259
thisCM.execCommand('indentAuto');
12601260
});
@@ -1268,7 +1268,7 @@ var ICEcoder = {
12681268

12691269
if (!line) {line = thisCM.getCursor().line}
12701270
thisCM.operation(function() {
1271-
thisCM.replaceRange(thisCM.getLine(line) + "\n", {line: line, ch: 0}, {line: line, ch: 1000000});
1271+
thisCM.replaceRange(thisCM.getLine(line) + "\n", {line: line, ch: 0}, {line: line, ch: 1000000}, "+input");
12721272
thisCM.execCommand('indentAuto');
12731273
});
12741274
},
@@ -1288,7 +1288,7 @@ var ICEcoder = {
12881288
} else {
12891289
if (!line) {line = thisCM.getCursor().line}
12901290
ch = thisCM.getCursor().ch;
1291-
thisCM.replaceRange(thisCM.getLine(line) + "\n" + thisCM.getLine(line), {line: line, ch: 0}, {line: line, ch: 1000000});
1291+
thisCM.replaceRange(thisCM.getLine(line) + "\n" + thisCM.getLine(line), {line: line, ch: 0}, {line: line, ch: 1000000}, "+input");
12921292
thisCM.setCursor(line + 1, ch);
12931293
}
12941294
},
@@ -1426,6 +1426,38 @@ var ICEcoder = {
14261426
}
14271427
},
14281428

1429+
// Return character num from start of doc to cursor
1430+
getCharNumFromCursor: function() {
1431+
return this.getThisCM().getRange({line: 0, ch: 0}, this.getThisCM().getCursor()).length;
1432+
},
1433+
1434+
// Set the cursor according to num of characters from start of doc
1435+
setCursorByCharNum: function(num) {
1436+
// Temp data store
1437+
this.charPos = {
1438+
len: 0,
1439+
thisLine: 0,
1440+
thisChar: 0
1441+
};
1442+
// For each line in editor
1443+
this.getThisCM().eachLine(function(line) {
1444+
// The number we're seeking if greater than prev linees we've considered plus this line
1445+
if (num > ICEcoder.charPos.len + (line.text + "\n").length) {
1446+
// Increment line
1447+
ICEcoder.charPos.thisLine++;
1448+
// It's equal to or greater than the number we're seeking, so on this line
1449+
} else if (ICEcoder.charPos.thisChar === 0) {
1450+
// Set char (to avoid setting more than once) and set cursor
1451+
ICEcoder.charPos.thisChar = num - ICEcoder.charPos.len;
1452+
ICEcoder.getThisCM().setCursor({line: ICEcoder.charPos.thisLine, ch: ICEcoder.charPos.thisChar})
1453+
}
1454+
// Build up length count
1455+
ICEcoder.charPos.len += (line.text + "\n").length;
1456+
});
1457+
// Remove temp data store
1458+
delete this.charPos;
1459+
},
1460+
14291461
// Determine which area of the document we're in
14301462
caretLocationType: function() {
14311463
let thisCM, caretLocType, caretChunk, fileName, fileExt;
@@ -1519,7 +1551,7 @@ var ICEcoder = {
15191551
for (let i = startLine; i <= endLine; i++) {
15201552
cM.replaceRange(cM.getLine(i).slice(0, commentCH.length) != commentCH
15211553
? commentCH + cM.getLine(i)
1522-
: cM.getLine(i).slice(commentCH.length, cM.getLine(i).length), {line:i, ch:0}, {line:i, ch:1000000});
1554+
: cM.getLine(i).slice(commentCH.length, cM.getLine(i).length), {line:i, ch:0}, {line:i, ch:1000000}, "+input");
15231555
}
15241556
// Language has block commenting
15251557
} else {
@@ -1532,13 +1564,13 @@ var ICEcoder = {
15321564
if (-1 < ["CSS", "SQL"].indexOf(this.caretLocType)) {
15331565
cM.replaceRange(lineContent.slice(0,commentBS.length) != commentBS
15341566
? commentBS + lineContent + commentBE
1535-
: lineContent.slice(commentBS.length, lCLen - commentBE.length), {line: linePos, ch: 0}, {line: linePos, ch: 1000000});
1567+
: lineContent.slice(commentBS.length, lCLen - commentBE.length), {line: linePos, ch: 0}, {line: linePos, ch: 1000000}, "+input");
15361568
adjustCursor = commentBS.length;
15371569
if (lineContent.slice(0,commentBS.length) == commentBS) {adjustCursor = -adjustCursor}
15381570
} else {
15391571
cM.replaceRange(lineContent.slice(0,commentCH.length) != commentCH
15401572
? commentCH + lineContent
1541-
: lineContent.slice(commentCH.length,lCLen), {line: linePos, ch: 0}, {line: linePos, ch: 1000000});
1573+
: lineContent.slice(commentCH.length,lCLen), {line: linePos, ch: 0}, {line: linePos, ch: 1000000}, "+input");
15421574
adjustCursor = commentCH.length;
15431575
if (lineContent.slice(0,commentCH.length) == commentCH) {adjustCursor = -adjustCursor}
15441576
}
@@ -1552,7 +1584,7 @@ var ICEcoder = {
15521584
} else {
15531585
cM.replaceRange(lineContent.slice(0,4) !== "<\!--"
15541586
? "<\!--" + lineContent + "//-->"
1555-
: lineContent.slice(4, lCLen-5), {line: linePos, ch: 0}, {line: linePos, ch: 1000000});
1587+
: lineContent.slice(4, lCLen-5), {line: linePos, ch: 0}, {line: linePos, ch: 1000000}, "+input");
15561588
adjustCursor = lineContent.slice(0,4) === "<\!--" ? -4 : 4;
15571589
}
15581590
}
@@ -2004,6 +2036,7 @@ var ICEcoder = {
20042036
// Save a file
20052037
saveFile: function(saveAs, newFileAutoSave) {
20062038
let changes, saveType, filePath, fileExt, pathPrefix;
2039+
let prettierVersion, editorText, prettierText, sm, opcodes, docShift, startShift, endShift, newContent;
20072040
filePath = this.openFiles[this.selectedTab - 1];
20082041
fileExt = filePath.substr(filePath.lastIndexOf(".") + 1);
20092042
if ("undefined" !== typeof prettier && ["js", "json", "ts", "css", "scss", "less", "html", "xml", "yaml", "md", "php"].indexOf(fileExt) > -1) {
@@ -2021,15 +2054,74 @@ var ICEcoder = {
20212054
case "php": parser = "php"; break;
20222055
}
20232056
try {
2024-
this.getThisCM().setValue(prettier.format(
2057+
prettierVersion = prettier.formatWithCursor(
20252058
this.getThisCM().getValue(),
20262059
{
20272060
parser: parser,
20282061
plugins: prettierPlugins,
20292062
tabWidth: this.indentSize,
2030-
useTabs: "tabs" === this.indentType
2063+
useTabs: "tabs" === this.indentType,
2064+
cursorOffset: this.getCharNumFromCursor()
2065+
}
2066+
);
2067+
2068+
// Get the text values and split it into lines
2069+
editorText = difflib.stringAsLines(this.getThisCM().getValue());
2070+
prettierText = difflib.stringAsLines(prettierVersion.formatted);
2071+
2072+
// Create a SequenceMatcher instance that diffs the two sets of lines
2073+
sm = new difflib.SequenceMatcher(editorText, prettierText);
2074+
2075+
// Get the opcodes from the SequenceMatcher instance
2076+
// Opcodes is a list of 3-tuples describing what changes should be made to the base text in order to yield the new text
2077+
opcodes = sm.get_opcodes();
2078+
docShift = 0;
2079+
2080+
for (let i = 0; i < opcodes.length; i++) {
2081+
// opcode events may be:
2082+
// equal = do nothing for this range
2083+
// replace = replace [1]-[2] with [3]-[4]
2084+
// insert = replace [1]-[2] with [3]-[4]
2085+
// delete = replace [1]-[2] with [3]-[4]
2086+
// Params to determine if we need to set 1 or 0 shift the start line and end line
2087+
startShift = "delete" === opcodes[i][0] && editorText.length === opcodes[i][2] ? 1 : 0;
2088+
endShift = "replace" === opcodes[i][0] ? 1 : 0;
2089+
if ("equal" !== opcodes[i][0]) {
2090+
// Replace or insert
2091+
if ("replace" === opcodes[i][0] || "insert" === opcodes[i][0]) {
2092+
newContent = "";
2093+
// For each of the replace/insert lines in Prettier's version
2094+
for (let j = opcodes[i][3]; j < opcodes[i][4]; j++) {
2095+
// Build up newContent lines and end with a new line char if not the last line in the range
2096+
newContent += prettierText[j];
2097+
if (j < opcodes[i][4] - 1) {
2098+
newContent += "\n";
2099+
}
2100+
}
2101+
}
2102+
// Delete
2103+
if ("delete" === opcodes[i][0]) {
2104+
// Not the last line in doc, the newContent is the line after the section we're deleting in editors version
2105+
// Else if it's the last line in doc, the content after the section we're deleting is nothing
2106+
newContent = editorText.length > opcodes[i][2]
2107+
? editorText[opcodes[i][2]]
2108+
: "";
2109+
}
2110+
console.log(startShift);
2111+
// Replace the range with newContent. The range start line and end line adjust addording to
2112+
// startShift and endShift 1/0 values plus also the +/- docShift which is how much the
2113+
// editor document has shifted so far during replace ranges
2114+
this.getThisCM().replaceRange(newContent, {line: opcodes[i][1] - docShift - startShift, ch: 0}, {line: opcodes[i][2] - docShift - endShift, ch: 1000000}, "+input");
2115+
// Work out the +/- document shift based on difference between the editors last line in
2116+
// this diff range and Prettiers last line in this diff range
2117+
docShift = opcodes[i][2] - opcodes[i][4];
20312118
}
2032-
));
2119+
}
2120+
// If we don't have text selected, we have a cursor, so move the cursor to new place in
2121+
// the prettified version now we've made adjustments
2122+
if (false === this.getThisCM().somethingSelected()) {
2123+
this.setCursorByCharNum(prettierVersion.cursorOffset);
2124+
}
20332125
} catch(err) {
20342126
get("toolLinkOutput").className = "highlight error";
20352127
this.outputMsg('<div style="background: #b00; padding: 1px 3px; border-radius: 3px; font-family: monospace;">Syntax error in ' + this.openFiles[this.selectedTab - 1].replace(iceRoot, "") + '</div>\n' + err.message.replace(/</g, '&lt;').replace(/>/g, '&gt;'));
@@ -3174,7 +3266,7 @@ var ICEcoder = {
31743266
thisCM = this.getThisCM();
31753267

31763268
cursor = thisCM.getTokenAt(thisCM.getCursor());
3177-
thisCM.replaceRange(color,{line:thisCM.getCursor().line,ch:cursor.start},{line:thisCM.getCursor().line,ch:cursor.end});
3269+
thisCM.replaceRange(color,{line:thisCM.getCursor().line,ch:cursor.start},{line:thisCM.getCursor().line,ch:cursor.end}, "+input");
31783270
},
31793271

31803272
// Change opacity of the file manager icons
@@ -4812,7 +4904,7 @@ var ICEcoder = {
48124904
}
48134905
}
48144906
// Clear the cursor string and set the cursor there
4815-
thisCM.replaceRange(replacedLine.replace("CURSOR",""),{line:lineNo,ch:0},{line:lineNo,ch:1000000});
4907+
thisCM.replaceRange(replacedLine.replace("CURSOR",""),{line:lineNo,ch:0},{line:lineNo,ch:1000000}, "+input");
48164908
thisCM.setCursor(lineNoCount,curPos);
48174909
// Finally, focus on the editor
48184910
this.focus(this.editorFocusInstance.indexOf('diff') > -1 ? true : false);
@@ -5103,10 +5195,10 @@ var ICEcoder = {
51035195
// Push a duplicate of tail onto end, to increase snake length by 1 block
51045196
this.snakePos.push([this.snakePos[this.snakePos.length-1][0],this.snakePos[this.snakePos.length-1][1]]);
51055197
// Replace char under head with nothing if end of line, else with our replacement string
5106-
cM.doc.replaceRange(this.snakePos[0][0]-1 == lineContent.length-2 ? "" : spaceReplaceChars,lineData,{line: lineData.line, ch: lineData.ch+1});
5198+
cM.doc.replaceRange(this.snakePos[0][0]-1 == lineContent.length-2 ? "" : spaceReplaceChars,lineData,{line: lineData.line, ch: lineData.ch+1}, "+input");
51075199
// Remove any trailing space at end
51085200
if (this.snakePos[0][0]-1 == lineContent.length-2) {
5109-
cM.doc.replaceRange(cM.getLine(lineData.line).replace(/[ \t]+$/,''),{line: lineData.line, ch: 0},{line: lineData.line, ch: 1000000});
5201+
cM.doc.replaceRange(cM.getLine(lineData.line).replace(/[ \t]+$/,''),{line: lineData.line, ch: 0},{line: lineData.line, ch: 1000000}, "+input");
51105202
}
51115203
} else {
51125204
// Reduce snake length if over 5 chars and not on content

0 commit comments

Comments
 (0)