PageRenderTime 31ms CodeModel.GetById 1ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-3-pre5/org/gjt/sp/jedit/buffer/LineManager.java

#
Java | 362 lines | 240 code | 48 blank | 74 comment | 63 complexity | 5e29eb47e722de66d1f29945fef44999 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * LineManager.java - Manages line info, line start offsets, positions
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2001, 2004 Slava Pestov
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. */
  22. package org.gjt.sp.jedit.buffer;
  23. //{{{ Imports
  24. import org.gjt.sp.jedit.syntax.*;
  25. import org.gjt.sp.jedit.Debug;
  26. import org.gjt.sp.util.IntegerArray;
  27. import org.gjt.sp.util.Log;
  28. //}}}
  29. /**
  30. * A class internal to jEdit's document model. You should not use it
  31. * directly. To improve performance, none of the methods in this class
  32. * check for out of bounds access, nor are they thread-safe. The
  33. * <code>Buffer</code> class, through which these methods must be
  34. * called through, implements such protection.
  35. *
  36. * @author Slava Pestov
  37. * @version $Id: LineManager.java 5484 2006-06-23 21:59:52Z kpouer $
  38. * @since jEdit 4.2pre3
  39. */
  40. public class LineManager
  41. {
  42. //{{{ LineManager constructor
  43. public LineManager()
  44. {
  45. endOffsets = new int[1];
  46. endOffsets[0] = 1;
  47. foldLevels = new short[1];
  48. lineContext = new TokenMarker.LineContext[1];
  49. lineCount = 1;
  50. } //}}}
  51. //{{{ getLineCount() method
  52. public final int getLineCount()
  53. {
  54. return lineCount;
  55. } //}}}
  56. //{{{ getLineOfOffset() method
  57. public int getLineOfOffset(int offset)
  58. {
  59. int start = 0;
  60. int end = lineCount - 1;
  61. for(;;)
  62. {
  63. switch(end - start)
  64. {
  65. case 0:
  66. if(getLineEndOffset(start) <= offset)
  67. return start + 1;
  68. else
  69. return start;
  70. case 1:
  71. if(getLineEndOffset(start) <= offset)
  72. {
  73. if(getLineEndOffset(end) <= offset)
  74. return end + 1;
  75. else
  76. return end;
  77. }
  78. else
  79. return start;
  80. default:
  81. int pivot = (end + start) / 2;
  82. int value = getLineEndOffset(pivot);
  83. if(value == offset)
  84. return pivot + 1;
  85. else if(value < offset)
  86. start = pivot + 1;
  87. else
  88. end = pivot - 1;
  89. break;
  90. }
  91. }
  92. } //}}}
  93. //{{{ getLineEndOffset() method
  94. public final int getLineEndOffset(int line)
  95. {
  96. if(gapLine != -1 && line >= gapLine)
  97. return endOffsets[line] + gapWidth;
  98. else
  99. return endOffsets[line];
  100. } //}}}
  101. //{{{ getFoldLevel() method
  102. public final int getFoldLevel(int line)
  103. {
  104. return foldLevels[line];
  105. } //}}}
  106. //{{{ setFoldLevel() method
  107. // Also sets 'fold level valid' flag
  108. public final void setFoldLevel(int line, int level)
  109. {
  110. if(level > 0xffff)
  111. {
  112. // limitations...
  113. level = 0xffff;
  114. }
  115. foldLevels[line] = (short)level;
  116. } //}}}
  117. //{{{ setFirstInvalidFoldLevel() method
  118. public void setFirstInvalidFoldLevel(int firstInvalidFoldLevel)
  119. {
  120. this.firstInvalidFoldLevel = firstInvalidFoldLevel;
  121. } //}}}
  122. //{{{ getFirstInvalidFoldLevel() method
  123. public int getFirstInvalidFoldLevel()
  124. {
  125. return firstInvalidFoldLevel;
  126. } //}}}
  127. //{{{ getLineContext() method
  128. public final TokenMarker.LineContext getLineContext(int line)
  129. {
  130. return lineContext[line];
  131. } //}}}
  132. //{{{ setLineContext() method
  133. public final void setLineContext(int line, TokenMarker.LineContext context)
  134. {
  135. lineContext[line] = context;
  136. } //}}}
  137. //{{{ setFirstInvalidLineContext() method
  138. public void setFirstInvalidLineContext(int firstInvalidLineContext)
  139. {
  140. this.firstInvalidLineContext = firstInvalidLineContext;
  141. } //}}}
  142. //{{{ getFirstInvalidLineContext() method
  143. public int getFirstInvalidLineContext()
  144. {
  145. return firstInvalidLineContext;
  146. } //}}}
  147. //{{{ _contentInserted() method
  148. public void _contentInserted(IntegerArray endOffsets)
  149. {
  150. gapLine = -1;
  151. gapWidth = 0;
  152. firstInvalidLineContext = firstInvalidFoldLevel = 0;
  153. lineCount = endOffsets.getSize();
  154. this.endOffsets = endOffsets.getArray();
  155. foldLevels = new short[lineCount];
  156. lineContext = new TokenMarker.LineContext[lineCount];
  157. } //}}}
  158. //{{{ contentInserted() method
  159. public void contentInserted(int startLine, int offset,
  160. int numLines, int length, IntegerArray endOffsets)
  161. {
  162. int endLine = startLine + numLines;
  163. //{{{ Update line info and line context arrays
  164. if(numLines > 0)
  165. {
  166. //moveGap(-1,0,"contentInserted");
  167. lineCount += numLines;
  168. if(this.endOffsets.length <= lineCount)
  169. {
  170. int[] endOffsetsN = new int[(lineCount + 1) * 2];
  171. System.arraycopy(this.endOffsets,0,endOffsetsN,0,
  172. this.endOffsets.length);
  173. this.endOffsets = endOffsetsN;
  174. }
  175. if(foldLevels.length <= lineCount)
  176. {
  177. short[] foldLevelsN = new short[(lineCount + 1) * 2];
  178. System.arraycopy(foldLevels,0,foldLevelsN,0,
  179. foldLevels.length);
  180. foldLevels = foldLevelsN;
  181. }
  182. if(lineContext.length <= lineCount)
  183. {
  184. TokenMarker.LineContext[] lineContextN
  185. = new TokenMarker.LineContext[(lineCount + 1) * 2];
  186. System.arraycopy(lineContext,0,lineContextN,0,
  187. lineContext.length);
  188. lineContext = lineContextN;
  189. }
  190. System.arraycopy(this.endOffsets,startLine,
  191. this.endOffsets,endLine,lineCount - endLine);
  192. System.arraycopy(foldLevels,startLine,foldLevels,
  193. endLine,lineCount - endLine);
  194. System.arraycopy(lineContext,startLine,lineContext,
  195. endLine,lineCount - endLine);
  196. if(startLine <= gapLine)
  197. gapLine += numLines;
  198. else if(gapLine != -1)
  199. offset -= gapWidth;
  200. if(startLine < firstInvalidLineContext)
  201. firstInvalidLineContext += numLines;
  202. for(int i = 0; i < numLines; i++)
  203. {
  204. this.endOffsets[startLine + i] = (offset + endOffsets.get(i));
  205. foldLevels[startLine + i] = 0;
  206. }
  207. } //}}}
  208. if(firstInvalidFoldLevel == -1 || firstInvalidFoldLevel > startLine)
  209. firstInvalidFoldLevel = startLine;
  210. moveGap(endLine,length,"contentInserted");
  211. } //}}}
  212. //{{{ contentRemoved() method
  213. public void contentRemoved(int startLine, int offset,
  214. int numLines, int length)
  215. {
  216. int endLine = startLine + numLines;
  217. //{{{ Update line info and line context arrays
  218. if(numLines > 0)
  219. {
  220. //moveGap(-1,0,"contentRemoved");
  221. if(startLine + numLines < gapLine)
  222. gapLine -= numLines;
  223. else if(startLine < gapLine)
  224. gapLine = startLine;
  225. if(startLine + numLines < firstInvalidLineContext)
  226. firstInvalidLineContext -= numLines;
  227. else if(startLine < firstInvalidLineContext)
  228. firstInvalidLineContext = startLine - 1;
  229. lineCount -= numLines;
  230. System.arraycopy(endOffsets,endLine,endOffsets,
  231. startLine,lineCount - startLine);
  232. System.arraycopy(foldLevels,endLine,foldLevels,
  233. startLine,lineCount - startLine);
  234. System.arraycopy(lineContext,endLine,lineContext,
  235. startLine,lineCount - startLine);
  236. } //}}}
  237. if(firstInvalidFoldLevel == -1 || firstInvalidFoldLevel > startLine)
  238. firstInvalidFoldLevel = startLine;
  239. moveGap(startLine,-length,"contentRemoved");
  240. } //}}}
  241. //{{{ Private members
  242. //{{{ Instance variables
  243. private int[] endOffsets;
  244. private short[] foldLevels;
  245. private TokenMarker.LineContext[] lineContext;
  246. private int lineCount;
  247. /**
  248. * If -1, then there is no gap.
  249. * Otherwise, all lines from this line onwards need to have gapWidth
  250. * added to their end offsets.
  251. */
  252. private int gapLine;
  253. private int gapWidth;
  254. /**
  255. * If -1, all contexts are valid. Otherwise, all lines after this have
  256. * an invalid context.
  257. */
  258. private int firstInvalidLineContext;
  259. /**
  260. * If -1, all fold levels are valid. Otherwise, all lines after this
  261. * have an invalid fold level.
  262. */
  263. private int firstInvalidFoldLevel;
  264. //}}}
  265. //{{{ setLineEndOffset() method
  266. private final void setLineEndOffset(int line, int end)
  267. {
  268. endOffsets[line] = end;
  269. } //}}}
  270. //{{{ moveGap() method
  271. private final void moveGap(int newGapLine, int newGapWidth, String method)
  272. {
  273. if(gapLine == -1)
  274. gapWidth = newGapWidth;
  275. else if(newGapLine == -1)
  276. {
  277. if(gapWidth != 0)
  278. {
  279. if(Debug.OFFSET_DEBUG && gapLine != lineCount)
  280. Log.log(Log.DEBUG,this,method + ": update from " + gapLine + " to " + lineCount + " width " + gapWidth);
  281. for(int i = gapLine; i < lineCount; i++)
  282. setLineEndOffset(i,getLineEndOffset(i));
  283. }
  284. gapWidth = newGapWidth;
  285. }
  286. else if(newGapLine < gapLine)
  287. {
  288. if(gapWidth != 0)
  289. {
  290. if(Debug.OFFSET_DEBUG && newGapLine != gapLine)
  291. Log.log(Log.DEBUG,this,method + ": update from " + newGapLine + " to " + gapLine + " width " + gapWidth);
  292. for(int i = newGapLine; i < gapLine; i++)
  293. setLineEndOffset(i,getLineEndOffset(i) - gapWidth);
  294. }
  295. gapWidth += newGapWidth;
  296. }
  297. else //if(newGapLine >= gapLine)
  298. {
  299. if(gapWidth != 0)
  300. {
  301. if(Debug.OFFSET_DEBUG && gapLine != newGapLine)
  302. Log.log(Log.DEBUG,this,method + ": update from " + gapLine + " to " + newGapLine + " width " + gapWidth);
  303. for(int i = gapLine; i < newGapLine; i++)
  304. setLineEndOffset(i,getLineEndOffset(i));
  305. }
  306. gapWidth += newGapWidth;
  307. }
  308. if(newGapLine == lineCount)
  309. gapLine = -1;
  310. else
  311. gapLine = newGapLine;
  312. } //}}}
  313. //}}}
  314. }