forked from akvelon/flutter-code-editor
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcode_lines.dart
82 lines (65 loc) · 2.11 KB
/
code_lines.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import 'dart:ui';
import 'package:characters/characters.dart';
import 'package:collection/collection.dart';
import 'package:equatable/equatable.dart';
import 'package:meta/meta.dart';
import 'code_line.dart';
@immutable
class CodeLines with EquatableMixin {
final List<CodeLine> lines;
const CodeLines(this.lines);
static const empty = CodeLines([
CodeLine(
text: '',
textRange: TextRange.collapsed(0),
indent: 0,
),
]);
CodeLine operator [](int i) => lines[i];
int get length => lines.length;
/// Returns the 0-based line number of the character at [characterIndex].
///
/// [characterIndex] can be from 0 to length inclusive.
/// If it is equal to length, it means the cursor at the end of the text.
///
/// Other values throw [RangeError].
int characterIndexToLineIndex(int characterIndex) {
int lowerLine = 0;
int upperLine = lines.length - 1;
while (true) {
final lowerCharacter = lines[lowerLine].textRange.start;
final upperCharacter = lines[upperLine].textRange.end;
if (upperCharacter == lowerCharacter) {
return lowerLine; // Empty line case, avoid division by zero.
}
// Linear interpolation search.
final lineIndex = lowerLine +
((upperLine - lowerLine) *
(characterIndex - lowerCharacter) /
(upperCharacter - lowerCharacter))
.floor();
final line = lines[lineIndex];
if (characterIndex < line.textRange.start) {
// Character is before the current line. Next search before it.
upperLine = lineIndex - 1;
continue;
}
if (characterIndex > line.textRange.end) {
// Character is after this line. Next search after it.
lowerLine = lineIndex + 1;
continue;
}
if (characterIndex == line.textRange.end) {
if (line.text.characters.lastOrNull == '\n') {
// Character is just after this string's \n, it is the next line.
return lineIndex + 1;
}
}
return lineIndex;
}
}
@override
List<Object> get props => [
lines,
];
}