diff options
author | Petter Rodhelind <petter.rodhelind@gmail.com> | 2018-02-22 23:15:13 +0100 |
---|---|---|
committer | Petter Rodhelind <petter.rodhelind@gmail.com> | 2018-02-22 23:15:13 +0100 |
commit | 4bca49f807544bd948a5f5f78e3787411252650f (patch) | |
tree | 5014acfd25b349488fd8116dccccac714bedb65d /testfiles/view.txt | |
download | poe-4bca49f807544bd948a5f5f78e3787411252650f.tar.gz poe-4bca49f807544bd948a5f5f78e3787411252650f.tar.bz2 poe-4bca49f807544bd948a5f5f78e3787411252650f.zip |
first commit
Diffstat (limited to 'testfiles/view.txt')
-rw-r--r-- | testfiles/view.txt | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/testfiles/view.txt b/testfiles/view.txt new file mode 100644 index 0000000..7cb4000 --- /dev/null +++ b/testfiles/view.txt @@ -0,0 +1,272 @@ +package main + +import ( + "github.com/gdamore/tcell" +) + +type View struct { + x, y int // position + w, h int + rows []int // cursor offset for beginning of each row + style tcell.Style + text *Text + scrollpos int // bytes to skip when drawing content + opos int // overflow + tabstop int + history History + focused bool + dirty bool +} + +func (b *View) Write(p []byte) (int, error) { + n, err := b.text.Write(p) + if err != nil { + return 0, err + } + b.dirty = true + return n, err +} + +func (b *View) Delete() (int, error) { + // Do not allow deletion beyond what we can see. + // This forces the user to scroll to visible content. + if b.text.cursorpos == b.scrollpos { + return 0, nil //silent return + } + n, err := b.text.Delete() + if err != nil { + return n, err + } + + b.dirty = true + + return n, nil +} + +func (b *View) SetStyle(style tcell.Style) { + b.style = style +} + +func (b *View) Resize(x, y, w, h int) { + b.x = x + b.y = y + b.w = w + b.h = h +} + +func (b *View) Size() (x, y, w, h int) { + return b.x, b.y, b.w, b.h +} + +// Byte returns the current byte under the cursor. +func (b *View) Byte() byte { + c, _ := b.text.buf.ByteAt(b.text.cursorpos) + return c +} + +func (b *View) Overflow() int { + return b.opos +} + +func (b *View) Cursor() int { + return b.text.cursorpos +} + +func (b *View) SetCursor(pos, whence int) { + b.text.SetCursor(pos, whence) + + // // scroll to cursor if out of screen + // if b.Cursor() < b.scrollpos || b.Cursor() >= b.Overflow() { + // //if b.Cursor() != b.buf.Len() { // do not autoscroll on +1 last byte + // b.ScrollTo(b.Cursor()) + // //} + // } +} + +// XYToOffset translates mouse coordinates in a 2D terminal to the correct byte offset in buffer. +func (b *View) XYToOffset(x, y int) int { + offset := b.scrollpos + + for y-b.y > 0 { + c, _ := b.text.buf.ByteAt(offset) + if c == '\n' { + offset++ + y-- + continue + } + xw := 0 + for ; c != '\n' && xw < b.x+b.w; offset++ { + c, _ = b.text.buf.ByteAt(offset) + xw++ + } + y-- + } + + for x-b.x > 0 { + c, _ := b.text.buf.ByteAt(offset) + if c == '\n' { + break + } + if c == '\t' { + x -= b.tabstop - 1 + } + offset++ + x-- + } + + return offset +} + +// Scroll will move the visible part of the buffer in number of lines. Negative means upwards. +func (b *View) Scroll(n int) { + offset := 0 + if n > 0 { + for n > 0 { + if c, _ := b.text.buf.ByteAt(b.scrollpos + offset); c == '\n' { + offset++ + } else { + offset += b.text.NextNL(b.scrollpos+offset) + 1 + } + n-- + } + b.scrollpos += offset + } + + if n < 0 { + offset += b.text.PrevNL(b.scrollpos) + for n < 0 { + offset += b.text.PrevNL(b.scrollpos - offset) + n++ + } + if b.scrollpos-offset > 0 { + b.scrollpos -= offset - 1 + } else { + b.scrollpos = 0 + } + } + + // boundaries + if b.scrollpos < 0 { + b.scrollpos = 0 + } + if b.scrollpos > b.text.buf.Len() { + b.scrollpos = b.text.buf.Len() + } +} + +// ScrollTo will scroll to an absolute byte offset in the buffer and backwards to the nearest previous newline. +func (b *View) ScrollTo(offset int) { + offset -= b.text.PrevNL(offset) + if offset > 0 { + offset += 1 + } + b.scrollpos = offset + b.Scroll(-(b.h / 3)) // scroll a third page more for context +} + +func (b *View) Draw() { + x, y := b.x, b.y + + // clear + for y := b.y; y <= b.h; y++ { + for x := b.x; x < b.w; x++ { + //draw vertical line separator + if b.x > 0 && x == b.x { + screen.SetContent(x, y, '|', nil, separatorStyle) + } else { + screen.SetContent(x, y, ' ', nil, b.style) + } + } + } + + if b.text.buf.Len() > 0 { + b.opos = b.scrollpos // keep track of last visible char/overflow + + for i := b.scrollpos; i < b.text.buf.Len(); i++ { + // line wrap + if x == b.x+b.w { + y += 1 + x = b.x + } + + // jump past separator if needed + // if b.x > 0 && x == b.x { + // x++ + // } + + // default style + style := b.style + + // highlight cursor + if i == b.text.cursorpos && b.focused { + style = cursorStyle + } + + // draw byte from buffer + c, err := b.text.buf.ByteAt(i) + if err != nil { + screen.SetContent(x, y, '?', nil, style) + printMsg("index out of range [%d]\n", i) + break + } + switch c { + case '\n': // linebreak + screen.SetContent(x, y, '\n', nil, style) + for j := x + 1; j < b.w; j++ { + screen.SetContent(j, y, ' ', nil, defStyle) // fill rest of line with blanks + } + + y += 1 + if y >= b.y+b.h { + break + } + x = b.x + b.w + for x > b.x { + screen.SetContent(x, y, ' ', nil, b.style) + x-- + } + case '\t': // show tab in tabstop width + screen.SetContent(x, y, '\t', nil, style) + x++ + for j := 0; j < b.tabstop-1; j++ { + screen.SetContent(x, y, ' ', nil, b.style) + x++ + } + default: + screen.SetContent(x, y, rune(c), nil, style) + x += 1 + } + + b.opos++ // increment last visible char/overflow + + // stop at bottom of box + if y >= b.y+b.h { + break + } + } + } + + // remove visual cursor clutter and fill out last line + for w := b.w; w >= x; w-- { + screen.SetContent(w, y, ' ', nil, b.style) + } + + // show cursor on EOF + if b.text.cursorpos == b.text.buf.Len() && b.focused { + screen.SetContent(x, y, ' ', nil, cursorStyle) + } + + // //begin empty lines with tilde, if more than one + // if b.h > 1 { + // y++ + // for ; y <= b.y+b.h; y++ { + // screen.SetContent(0, y, '~', nil, defStyle) + // //remove visual trailing clutter on line below + // x = b.x + b.w + // for x > 0 { + // screen.SetContent(x, y, ' ', nil, defStyle) + // x-- + // } + // } + // } +} |