diff options
Diffstat (limited to 'viewport/viewport.go')
| -rw-r--r-- | viewport/viewport.go | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/viewport/viewport.go b/viewport/viewport.go new file mode 100644 index 0000000..ff1ca05 --- /dev/null +++ b/viewport/viewport.go @@ -0,0 +1,67 @@ +package viewport + +import ( + "strings" +) + +const Caret = "⏵" + +func NeedsViewport(input string, height int) bool { + lines := strings.Split(input, "\n") + return len(lines)-1 > height +} + +func Process(input string, height int) string { + lines := strings.Split(input, "\n") + if len(lines) > height { + cropped, top, bottom := Crop(input, lines, height) + return WithScroll(cropped, int(top*float32(height)), int(bottom*float32(height))) + } + return input +} + +func Focus(lines []string, needle string) int { + for i, l := range lines { + if strings.Contains(l, needle) { + return i + } + } + return -1 +} + +func Crop(input string, lines []string, height int) (output string, scrollStart float32, scrollEnd float32) { + output = input + selectionIndex := Focus(lines, Caret) + size := len(lines) + if size <= height { + return output, 0, 1 + } + + linesAbove := height / 2 + linesBelow := height - linesAbove + if linesAbove*2 < selectionIndex { + linesBelow++ + } + + start := selectionIndex - linesAbove + end := selectionIndex + linesBelow + + if start < 0 { + end += -start + start = 0 + } + + if end >= size { + diff := size - 1 - end + start += diff + end += diff + } + + scrollStart = float32(start) / float32(size) + scrollEnd = float32(end)/float32(size) + float32(1)/float32(size) + if scrollEnd > 1 { + scrollEnd = 1 + } + + return strings.Join(lines[start:end], "\n"), scrollStart, scrollEnd +} |
