| 1 |
// CodeMirror, copyright (c) by Marijn Haverbeke and others |
| 2 |
// Distributed under an MIT license: http://codemirror.net/LICENSE |
| 3 |
|
| 4 |
(function(mod) { |
| 5 |
if (typeof exports == "object" && typeof module == "object") // CommonJS |
| 6 |
mod(require("../../lib/codemirror")); |
| 7 |
else if (typeof define == "function" && define.amd) // AMD |
| 8 |
define(["../../lib/codemirror"], mod); |
| 9 |
else // Plain browser env |
| 10 |
mod(CodeMirror); |
| 11 |
})(function(CodeMirror) { |
| 12 |
"use strict"; |
| 13 |
|
| 14 |
var Pos = CodeMirror.Pos; |
| 15 |
|
| 16 |
function findParagraph(cm, pos, options) { |
| 17 |
var startRE = options.paragraphStart || cm.getHelper(pos, "paragraphStart"); |
| 18 |
for (var start = pos.line, first = cm.firstLine(); start > first; --start) { |
| 19 |
var line = cm.getLine(start); |
| 20 |
if (startRE && startRE.test(line)) break; |
| 21 |
if (!/\S/.test(line)) { ++start; break; } |
| 22 |
} |
| 23 |
var endRE = options.paragraphEnd || cm.getHelper(pos, "paragraphEnd"); |
| 24 |
for (var end = pos.line + 1, last = cm.lastLine(); end <= last; ++end) { |
| 25 |
var line = cm.getLine(end); |
| 26 |
if (endRE && endRE.test(line)) { ++end; break; } |
| 27 |
if (!/\S/.test(line)) break; |
| 28 |
} |
| 29 |
return {from: start, to: end}; |
| 30 |
} |
| 31 |
|
| 32 |
function findBreakPoint(text, column, wrapOn, killTrailingSpace) { |
| 33 |
var at = column |
| 34 |
while (at < text.length && text.charAt(at) == " ") at++ |
| 35 |
for (; at > 0; --at) |
| 36 |
if (wrapOn.test(text.slice(at - 1, at + 1))) break; |
| 37 |
for (var first = true;; first = false) { |
| 38 |
var endOfText = at; |
| 39 |
if (killTrailingSpace) |
| 40 |
while (text.charAt(endOfText - 1) == " ") --endOfText; |
| 41 |
if (endOfText == 0 && first) at = column; |
| 42 |
else return {from: endOfText, to: at}; |
| 43 |
} |
| 44 |
} |
| 45 |
|
| 46 |
function wrapRange(cm, from, to, options) { |
| 47 |
from = cm.clipPos(from); to = cm.clipPos(to); |
| 48 |
var column = options.column || 80; |
| 49 |
var wrapOn = options.wrapOn || /\s\S|-[^\.\d]/; |
| 50 |
var killTrailing = options.killTrailingSpace !== false; |
| 51 |
var changes = [], curLine = "", curNo = from.line; |
| 52 |
var lines = cm.getRange(from, to, false); |
| 53 |
if (!lines.length) return null; |
| 54 |
var leadingSpace = lines[0].match(/^[ \t]*/)[0]; |
| 55 |
|
| 56 |
for (var i = 0; i < lines.length; ++i) { |
| 57 |
var text = lines[i], oldLen = curLine.length, spaceInserted = 0; |
| 58 |
if (curLine && text && !wrapOn.test(curLine.charAt(curLine.length - 1) + text.charAt(0))) { |
| 59 |
curLine += " "; |
| 60 |
spaceInserted = 1; |
| 61 |
} |
| 62 |
var spaceTrimmed = ""; |
| 63 |
if (i) { |
| 64 |
spaceTrimmed = text.match(/^\s*/)[0]; |
| 65 |
text = text.slice(spaceTrimmed.length); |
| 66 |
} |
| 67 |
curLine += text; |
| 68 |
if (i) { |
| 69 |
var firstBreak = curLine.length > column && leadingSpace == spaceTrimmed && |
| 70 |
findBreakPoint(curLine, column, wrapOn, killTrailing); |
| 71 |
// If this isn't broken, or is broken at a different point, remove old break |
| 72 |
if (!firstBreak || firstBreak.from != oldLen || firstBreak.to != oldLen + spaceInserted) { |
| 73 |
changes.push({text: [spaceInserted ? " " : ""], |
| 74 |
from: Pos(curNo, oldLen), |
| 75 |
to: Pos(curNo + 1, spaceTrimmed.length)}); |
| 76 |
} else { |
| 77 |
curLine = leadingSpace + text; |
| 78 |
++curNo; |
| 79 |
} |
| 80 |
} |
| 81 |
while (curLine.length > column) { |
| 82 |
var bp = findBreakPoint(curLine, column, wrapOn, killTrailing); |
| 83 |
changes.push({text: ["", leadingSpace], |
| 84 |
from: Pos(curNo, bp.from), |
| 85 |
to: Pos(curNo, bp.to)}); |
| 86 |
curLine = leadingSpace + curLine.slice(bp.to); |
| 87 |
++curNo; |
| 88 |
} |
| 89 |
} |
| 90 |
if (changes.length) cm.operation(function() { |
| 91 |
for (var i = 0; i < changes.length; ++i) { |
| 92 |
var change = changes[i]; |
| 93 |
if (change.text || CodeMirror.cmpPos(change.from, change.to)) |
| 94 |
cm.replaceRange(change.text, change.from, change.to); |
| 95 |
} |
| 96 |
}); |
| 97 |
return changes.length ? {from: changes[0].from, to: CodeMirror.changeEnd(changes[changes.length - 1])} : null; |
| 98 |
} |
| 99 |
|
| 100 |
CodeMirror.defineExtension("wrapParagraph", function(pos, options) { |
| 101 |
options = options || {}; |
| 102 |
if (!pos) pos = this.getCursor(); |
| 103 |
var para = findParagraph(this, pos, options); |
| 104 |
return wrapRange(this, Pos(para.from, 0), Pos(para.to - 1), options); |
| 105 |
}); |
| 106 |
|
| 107 |
CodeMirror.commands.wrapLines = function(cm) { |
| 108 |
cm.operation(function() { |
| 109 |
var ranges = cm.listSelections(), at = cm.lastLine() + 1; |
| 110 |
for (var i = ranges.length - 1; i >= 0; i--) { |
| 111 |
var range = ranges[i], span; |
| 112 |
if (range.empty()) { |
| 113 |
var para = findParagraph(cm, range.head, {}); |
| 114 |
span = {from: Pos(para.from, 0), to: Pos(para.to - 1)}; |
| 115 |
} else { |
| 116 |
span = {from: range.from(), to: range.to()}; |
| 117 |
} |
| 118 |
if (span.to.line >= at) continue; |
| 119 |
at = span.from.line; |
| 120 |
wrapRange(cm, span.from, span.to, {}); |
| 121 |
} |
| 122 |
}); |
| 123 |
}; |
| 124 |
|
| 125 |
CodeMirror.defineExtension("wrapRange", function(from, to, options) { |
| 126 |
return wrapRange(this, from, to, options || {}); |
| 127 |
}); |
| 128 |
|
| 129 |
CodeMirror.defineExtension("wrapParagraphsInRange", function(from, to, options) { |
| 130 |
options = options || {}; |
| 131 |
var cm = this, paras = []; |
| 132 |
for (var line = from.line; line <= to.line;) { |
| 133 |
var para = findParagraph(cm, Pos(line, 0), options); |
| 134 |
paras.push(para); |
| 135 |
line = para.to; |
| 136 |
} |
| 137 |
var madeChange = false; |
| 138 |
if (paras.length) cm.operation(function() { |
| 139 |
for (var i = paras.length - 1; i >= 0; --i) |
| 140 |
madeChange = madeChange || wrapRange(cm, Pos(paras[i].from, 0), Pos(paras[i].to - 1), options); |
| 141 |
}); |
| 142 |
return madeChange; |
| 143 |
}); |
| 144 |
}); |
| 145 |
|