1 type Text = 2 val lines = 3 let line = TextLine.new 4 line.insert 0 '\n' 5 mut_list_of line 6 7 fun get (i : u32) = lines[i] 8 fun get (position : TextPos) = lines[position.line][position.char].char 9 10 def clear = 11 lines.clear 12 let line = TextLine.new 13 line.insert 0 '\n' 14 lines.add line 15 16 def set_color (line : u32) (color : u8) = 17 let l = lines[line] 18 for i = 0 until l.length do 19 l.set_color i color 20 21 def is_not_empty = 22 lines.size > 1 || lines.size > 0 && lines[0].length > 0 23 24 def max = TextPos (lines.size - 1) (lines.last.length - 1) 25 26 def line_max_index (line : u32) = 27 TextPos line (lines[line].length - 1) 28 29 def assert_end_of_line_chars = 30 for line in lines do 31 assert line.last == '\n' 32 33 def insert (position : TextPos) (c : Char) = 34 let line = lines[position.line] 35 line.insert position.char c 36 if c == '\n' then 37 let s = line.as_string 38 assert s.length > position.char + 1 39 let next_line = TextLine.new 40 next_line.insert 0 (s.drop (position.char + 1)) 41 line.remove_from (position.char + 1) 42 lines.add (position.line + 1) next_line 43 assert self[line_max_index position.line] == '\n' 44 assert self[line_max_index (position.line + 1)] == '\n' 45 46 assert_end_of_line_chars 47 48 def insert (position : TextPos) (s : String) = 49 let mut next = position 50 for c in s.chars.filter { _.is_ascii } do 51 lines[next.line].insert next.char c 52 if c == '\n' then 53 let line = lines[next.line] 54 let next_line = TextLine.new 55 for i = next.char + 1 until line.length do 56 next_line.insert (i - next.char - 1) line[i] 57 58 line.remove_from (next.char + 1) 59 lines.add (next.line + 1) next_line 60 next = TextPos (next.line + 1) 0 61 else 62 next = next.right 63 64 assert_end_of_line_chars 65 66 next 67 68 def append (s : String) = 69 let index = line_max_index (lines.size - 1) 70 insert index s |> ignore 71 72 def append (c : Char) = 73 let index = line_max_index (lines.size - 1) 74 insert index c 75 76 def remove (position : TextPos) = 77 let c = self[position] 78 lines[position.line].remove position.char 79 if c == '\n' then 80 let line = lines[position.line + 1] 81 lines.remove_at (position.line + 1) 82 lines[position.line].insert position.char line.as_string 83 84 assert_end_of_line_chars 85 86 def remove_range (from : TextPos) (to : TextPos) = 87 assert from < to 88 if from.line == to.line then 89 let line = lines[from.line] 90 line.remove_range from.char to.char 91 return 92 93 let first_line = lines[from.line] 94 first_line.remove_from from.char 95 let last_line = lines[to.line] 96 first_line.insert from.char (last_line.as_string.drop to.char) 97 lines.remove_at to.line 98 for _ = 0 until to.line - from.line - 1 do 99 lines.remove_at (from.line + 1) 100 101 assert_end_of_line_chars 102 103 def last_pos = 104 let line = lines.size - 1 105 TextPos line (lines[line].length - 1) 106 107 def prev (position : TextPos) = when 108 position.char > 0 -> position.left 109 position.line > 0 -> line_max_index (position.line - 1) 110 else -> fail position 111 112 def next (position : TextPos) = 113 let line = lines[position.line] 114 when 115 position.char < line.length - 1 -> position.right 116 position.line < lines.size - 1 -> TextPos (position.line + 1) 0 117 else -> fail position 118 119 def range (from : TextPos) (to : TextPos) = 120 assert from < to 121 let sb = StringBuilder.new 122 if from.line == to.line then 123 let line = lines[from.line] 124 for i = from.char until to.char do 125 sb.append line[i].char 126 127 return sb.create 128 129 let first_line = lines[from.line] 130 for i = from.char until first_line.length do 131 sb.append first_line[i].char 132 133 for i = from.line + 1 until to.line do 134 let line = lines[i] 135 sb.append line.as_string 136 137 let last_line = lines[to.line] 138 for i = 0 until to.char do 139 sb.append last_line[i].char 140 141 sb.create 142 143 def trim_end = 144 let mut index = lines.size - 1 145 while index > 0 146 && lines[index].is_blank 147 && lines[index - 1].is_blank 148 do 149 index -= 1 150 151 let count = lines.size - 1 - index 152 for _ = 0 until count do 153 lines.remove_at (lines.size - 1) 154 155 let last_line = lines[lines.size - 1] 156 if last_line.is_blank && last_line.as_string <> "\n" then 157 last_line.trim_end 158 159 def ends_with_blank_line = lines[lines.size - 1].is_blank 160 161 def ends_with_two_blank_lines = 162 lines.size > 1 && ends_with_blank_line && lines[lines.size - 2].is_blank 163 164 def add_empty_line = 165 let line = TextLine.new 166 line.insert 0 '\n' 167 lines.add line 168