hardwrap.js 6.7 KB

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