Advertisement
Guest User

res

a guest
May 15th, 2019
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 5.42 KB | None | 0 0
  1.  
  2.  
  3. // PlaneText.scala
  4. // Copyright (c) 2015 J. M. Spivey
  5.  
  6. /** An extension of Text that keeps track of the division of the
  7.  * text into lines. */
  8. class PlaneText(init: Int) extends Text() {
  9.     /* For present purposes, we count each newline character as part of the
  10.      * line it terminates, so that every line has non-zero length.  Let's
  11.      * also imagine that a special terminator character is added to the end of
  12.      * the text, so that the very last line also has non-zero length.  For an
  13.      * ordinary text file that ends in a newline, this last line will be empty
  14.      * and be counted as having length 1, and the editor will count the
  15.      * file as having one more line than there are newline characters. */
  16.     private var nlines = 1
  17.     private var linelen = new Array[Int](init)
  18.     linelen(0) = 1
  19.    
  20.     /* For efficiency, we keep track of the beginning of the most recent line
  21.      * that was accessed.  This will help a lot if accesses are clustered.
  22.      * The invariant is linestart = sum linelen[0..curline) */
  23.     private var curline = 0
  24.     private var linestart = 0
  25.    
  26.     def this() { this(1000) }
  27.    
  28.     /** Return the number of lines, including the fictitious last line. */
  29.     def numLines = nlines
  30.    
  31.     /** Return the length of a line in the file */
  32.     def getLineLength(n: Int) = linelen(n)
  33.    
  34.     /** Find the line number corresponding to a character index. */
  35.     def getRow(pos: Int) = {
  36.         findPos(pos); curline
  37.     }
  38.    
  39.     /** Find the column number of a character index in its line. */
  40.     def getColumn(pos: Int) = {
  41.         findPos(pos); pos - linestart
  42.     }
  43.    
  44.     // Augment the mutator methods of Text to maintain the line map
  45.    
  46.     override def clear() {
  47.         super.clear()
  48.         nlines = 1
  49.         linelen(0) = 1
  50.         curline = 0
  51.         linestart = 0
  52.     }
  53.    
  54.     override def insert(pos: Int, ch: Char) {
  55.         super.insert(pos, ch)
  56.         findPos(pos)
  57.         if (ch != '\n')
  58.             linelen(curline) += 1
  59.         else
  60.             mapLines()
  61.     }
  62.  
  63.     override def insert(pos: Int, s: String) {
  64.         super.insert(pos, s)
  65.         mapLines()
  66.     }
  67.    
  68.     override def insertRange(pos: Int, t: Text, start: Int, nchars: Int) {
  69.         super.insertRange(pos, t, start, nchars)
  70.         mapLines()
  71.     }
  72.  
  73.     override def insertFile(pos: Int, in: java.io.Reader) {
  74.         try {
  75.             super.insertFile(pos, in)
  76.         } finally {
  77.             // Even if an IOException is thrown, we still update the line map
  78.             mapLines()
  79.         }
  80.     }
  81.    
  82.     override def deleteChar(pos: Int) {
  83.         val ch = charAt(pos)
  84.         super.deleteChar(pos)
  85.         findPos(pos)
  86.         if (ch != '\n')
  87.             linelen(curline) -= 1
  88.         else
  89.             mapLines()
  90.     }
  91.  
  92.     override def deleteRange(start: Int, len: Int) {
  93.         super.deleteRange(start, len)
  94.        
  95.         findPos(start)
  96.         if (start + len < linestart + linelen(curline))
  97.             linelen(curline) -= len
  98.         else
  99.             mapLines()
  100.     }
  101.  
  102.  
  103.     /** Return the editing position closest to the specified coordinates */
  104.     def getPos(row: Int, col: Int) = {
  105.         val r = Math.min(Math.max(row, 0), nlines-1)
  106.         findLine(r)
  107.         val c = Math.min(Math.max(col, 0), linelen(curline)-1)
  108.         linestart + c
  109.     }
  110.    
  111.     /** Fetch the text of line n, without the trailing newline */
  112.     def fetchLine(n: Int, buf: Text) {
  113.         findLine(n)
  114.         getRange(linestart, linelen(n)-1, buf)
  115.     }
  116.    
  117.     /** Refresh the line map by scanning the whole file.
  118.      * This is always a last resort if we choose not to update the
  119.      * line map in a faster way. */
  120.     private def mapLines() {
  121.         nlines = 0
  122.         var c = 0
  123.  
  124.         for (i <- 0 until length) {
  125.             c += 1
  126.             if (charAt(i) == '\n') {
  127.                 lineRoom()
  128.                 linelen(nlines) = c
  129.                 nlines += 1; c = 0
  130.             }
  131.         }
  132.        
  133.         lineRoom()
  134.         linelen(nlines) = c+1
  135.         nlines += 1
  136.        
  137.         // Reset the cache
  138.         curline = 0; linestart = 0
  139.     }
  140.    
  141.     /** Set curline to a specified line number. */
  142.     private def findLine(n: Int) {
  143.         assert(n >= 0 && n < nlines)
  144.        
  145.         // Move forwards if necessary
  146.         while (n > curline) {
  147.             linestart += linelen(curline)
  148.             curline += 1
  149.         }
  150.  
  151.         // Move backwards if necessary
  152.         while (n < curline) {
  153.             curline -= 1
  154.             linestart -= linelen(curline)
  155.         }
  156.     }
  157.    
  158.     /** Set current line so that it contains a specified character index. */
  159.     private def findPos(j: Int) {
  160.         assert(j >= 0 && j <= length)
  161.  
  162.         // Move forwards if necessary
  163.         while (j >= linestart + linelen(curline)) {
  164.             linestart += linelen(curline)
  165.             curline += 1
  166.         }
  167.        
  168.         // Move backwards if necessary
  169.         while (j < linestart) {
  170.             curline -= 1
  171.             linestart -= linelen(curline)
  172.         }
  173.        
  174.         assert(linestart <= j && j < linestart + linelen(curline))
  175.     }
  176.    
  177.     /** Find room for one more line */
  178.     private def lineRoom() {
  179.         if (nlines >= linelen.length) {
  180.             val newlen = new Array[Int](2*linelen.length)
  181.             Array.copy(linelen, 0, newlen, 0, nlines)
  182.             linelen = newlen
  183.         }
  184.     }
  185. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement