diff --git a/CHANGELOG.md b/CHANGELOG.md index f881ae48..8d85657d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.1.4] - 29.07.2023 + +[Diff](https://github.com/elk-language/go-prompt/compare/v1.1.3...elk-language:go-prompt:v1.1.4) + +### Added +- `func (*prompt.Document).PreviousLineIndentSpaces() int` +- `func (*prompt.Document).PreviousLineIndentLevel(indentSize int) int` +- `func (*prompt.Document).PreviousLine() (s string, ok bool)` + ## [1.1.3] - 29.07.2023 [Diff](https://github.com/elk-language/go-prompt/compare/v1.1.2...elk-language:go-prompt:v1.1.3) diff --git a/document.go b/document.go index 59e973b3..4798b73e 100644 --- a/document.go +++ b/document.go @@ -109,6 +109,25 @@ func (d *Document) CurrentLineIndentLevel(indentSize int) int { return d.IndentLevel(d.TextBeforeCursor(), indentSize) } +// Returns the amount of spaces that the previous line (relative to the cursor) +// is indented with. +func (d *Document) PreviousLineIndentSpaces() int { + line, ok := d.PreviousLine() + if !ok { + return 0 + } + return d.IndentSpaces(line) +} + +// Returns the indentation level of the previous line (relative to the cursor). +func (d *Document) PreviousLineIndentLevel(indentSize int) int { + line, ok := d.PreviousLine() + if !ok { + return 0 + } + return d.IndentLevel(line, indentSize) +} + // TextBeforeCursor returns the text before the cursor. func (d *Document) TextBeforeCursor() string { r := []rune(d.Text) @@ -349,6 +368,21 @@ func (d *Document) CurrentLine() string { return d.CurrentLineBeforeCursor() + d.CurrentLineAfterCursor() } +// Return the text of the previous line (relative to the cursor). +// If the cursor is on the first line then false is returned in the second value +// to signify that there is no previous line. +func (d *Document) PreviousLine() (s string, ok bool) { + indices := d.lineStartIndices() + pos := bisect.Right(indices, d.cursorPosition) - 1 + if pos == 0 { + return "", false + } + + prevLineStartIndex := indices[pos-1] + lineStartIndex := indices[pos] + return d.Text[prevLineStartIndex : lineStartIndex-1], true +} + // Array pointing to the start indices of all the lines. func (d *Document) lineStartIndices() []istrings.RuneNumber { // TODO: Cache, because this is often reused. diff --git a/document_test.go b/document_test.go index db890260..c14882e1 100644 --- a/document_test.go +++ b/document_test.go @@ -377,6 +377,46 @@ func TestDocument_LastLineIndentLevel(t *testing.T) { } } +func TestDocument_PreviousLine(t *testing.T) { + tests := []struct { + document *Document + want string + ok bool + }{ + { + document: &Document{ + Text: "line 1\nline 2\nline 3\n line 4", + cursorPosition: 32, + }, + want: "line 3", + ok: true, + }, + { + document: &Document{ + Text: "line 1\nline 2\nline 3\n line 4", + cursorPosition: 19, + }, + want: "line 2", + ok: true, + }, + { + document: &Document{ + Text: "line 1\nline 2\nline 3\n line 4", + cursorPosition: 1, + }, + want: "", + ok: false, + }, + } + + for i, tc := range tests { + got, ok := tc.document.PreviousLine() + if got != tc.want || ok != tc.ok { + t.Errorf("[%d] Should be (%#v, %#v), got (%#v, %#v)", i, tc.want, tc.ok, got, ok) + } + } +} + func TestDocument_TextAfterCursor(t *testing.T) { pattern := []struct { document *Document