diff --git a/internal/action/actions.go b/internal/action/actions.go index 6d83ae4c..c8cd6b5d 100644 --- a/internal/action/actions.go +++ b/internal/action/actions.go @@ -40,7 +40,7 @@ func (h *BufPane) ScrollDown(n int) { func (h *BufPane) MousePress(e *tcell.EventMouse) bool { b := h.Buf mx, my := e.Position() - mouseLoc := h.GetMouseLoc(buffer.Loc{mx, my}) + mouseLoc := h.LocFromVisual(buffer.Loc{mx, my}) h.Cursor.Loc = mouseLoc if h.mouseReleased { if b.NumCursors() > 1 { @@ -1410,7 +1410,7 @@ func (h *BufPane) SpawnMultiCursorSelect() bool { func (h *BufPane) MouseMultiCursor(e *tcell.EventMouse) bool { b := h.Buf mx, my := e.Position() - mouseLoc := h.GetMouseLoc(buffer.Loc{X: mx, Y: my}) + mouseLoc := h.LocFromVisual(buffer.Loc{X: mx, Y: my}) c := buffer.NewCursor(b, mouseLoc) b.AddCursor(c) b.MergeCursors() diff --git a/internal/action/bufpane.go b/internal/action/bufpane.go index fd6b6019..17a0220d 100644 --- a/internal/action/bufpane.go +++ b/internal/action/bufpane.go @@ -241,7 +241,7 @@ func (h *BufPane) HandleEvent(event tcell.Event) { // Mouse was just released mx, my := e.Position() - mouseLoc := h.GetMouseLoc(buffer.Loc{X: mx, Y: my}) + mouseLoc := h.LocFromVisual(buffer.Loc{X: mx, Y: my}) // Relocating here isn't really necessary because the cursor will // be in the right place from the last mouse event diff --git a/internal/action/tab.go b/internal/action/tab.go index 45a9f3db..bf0ffbec 100644 --- a/internal/action/tab.go +++ b/internal/action/tab.go @@ -103,7 +103,7 @@ func (t *TabList) HandleEvent(event tcell.Event) { mx, my := e.Position() switch e.Buttons() { case tcell.Button1: - ind := t.GetMouseLoc(buffer.Loc{mx, my}) + ind := t.LocFromVisual(buffer.Loc{mx, my}) if ind != -1 { t.SetActive(ind) } diff --git a/internal/display/bufwindow.go b/internal/display/bufwindow.go index 5c958147..ac1305a0 100644 --- a/internal/display/bufwindow.go +++ b/internal/display/bufwindow.go @@ -25,10 +25,8 @@ type BufWindow struct { sline *StatusLine - lineHeight []int - hasCalcHeight bool - gutterOffset int - drawStatus bool + gutterOffset int + drawStatus bool } // NewBufWindow creates a new window at a location in the screen with a width and height @@ -36,7 +34,6 @@ func NewBufWindow(x, y, width, height int, buf *buffer.Buffer) *BufWindow { w := new(BufWindow) w.View = new(View) w.X, w.Y, w.Width, w.Height, w.Buf = x, y, width, height, buf - w.lineHeight = make([]int, height) w.active = true w.sline = NewStatusLine(w) @@ -58,10 +55,6 @@ func (v *View) SetView(view *View) { func (w *BufWindow) Resize(width, height int) { w.Width, w.Height = width, height - w.lineHeight = make([]int, height) - w.hasCalcHeight = false - // This recalculates lineHeight - w.GetMouseLoc(buffer.Loc{width, height}) w.Relocate() } @@ -120,8 +113,7 @@ func (w *BufWindow) Clear() { // but if softwrap is enabled things get complicated since one buffer // line can take up multiple lines in the view func (w *BufWindow) Bottomline() int { - // TODO: possible non-softwrap optimization - if !w.Buf.Settings["softwrap"].(bool) || !w.hasCalcHeight { + if !w.Buf.Settings["softwrap"].(bool) { h := w.StartLine + w.Height - 1 if w.drawStatus { h-- @@ -129,15 +121,10 @@ func (w *BufWindow) Bottomline() int { return h } - prev := 0 - for _, l := range w.lineHeight { - if l >= prev { - prev = l - } else { - break - } - } - return prev + l := w.LocFromVisual(buffer.Loc{0, w.Height}) + + log.Println("Bottom line:", l.Y) + return l.Y } // Relocate moves the view window so that the cursor is in view @@ -152,7 +139,7 @@ func (w *BufWindow) Relocate() bool { if w.drawStatus { h-- } - if b.LinesNum() <= h || !w.hasCalcHeight { + if b.LinesNum() <= h { height = w.Height } ret := false @@ -189,15 +176,15 @@ func (w *BufWindow) Relocate() bool { return ret } -func (w *BufWindow) GetMouseLoc(svloc buffer.Loc) buffer.Loc { +// LocFromVisual takes a visual location (x and y position) and returns the +// position in the buffer corresponding to the visual location +// Computing the buffer location requires essentially drawing the entire screen +// to account for complications like softwrap, wide characters, and horizontal scrolling +// If the requested position does not correspond to a buffer location it returns +// the nearest position +func (w *BufWindow) LocFromVisual(svloc buffer.Loc) buffer.Loc { b := w.Buf - // TODO: possible non-softwrap optimization - // if !b.Settings["softwrap"].(bool) { - // l := b.LineBytes(svloc.Y) - // return buffer.Loc{b.GetActiveCursor().GetCharPosInLine(l, svloc.X), svloc.Y} - // } - hasMessage := len(b.Messages) > 0 bufHeight := w.Height if w.drawStatus { @@ -293,11 +280,12 @@ func (w *BufWindow) GetMouseLoc(svloc buffer.Loc) buffer.Loc { return bloc } + if bloc.Y+1 >= b.LinesNum() || vloc.Y+1 >= bufHeight { + return bloc + } + bloc.X = w.StartCol bloc.Y++ - if bloc.Y >= b.LinesNum() { - break - } } return buffer.Loc{} @@ -378,7 +366,6 @@ func (w *BufWindow) displayBuffer() { bufWidth-- } - w.hasCalcHeight = true if b.Settings["syntax"].(bool) && b.SyntaxDef != nil { for _, c := range b.GetCursors() { // rehighlight starting from where the cursor is @@ -544,8 +531,6 @@ func (w *BufWindow) displayBuffer() { nColsBeforeStart-- } - w.lineHeight[vloc.Y] = bloc.Y - totalwidth := w.StartCol - nColsBeforeStart for len(line) > 0 { r, size := utf8.DecodeRune(line) @@ -586,7 +571,6 @@ func (w *BufWindow) displayBuffer() { break } vloc.X = 0 - w.lineHeight[vloc.Y] = bloc.Y // This will draw an empty line number because the current line is wrapped w.drawLineNum(lineNumStyle, true, maxLineNumLength, &vloc, &bloc) } diff --git a/internal/display/infowindow.go b/internal/display/infowindow.go index db2f9c08..b179c81e 100644 --- a/internal/display/infowindow.go +++ b/internal/display/infowindow.go @@ -65,7 +65,7 @@ func (i *InfoWindow) SetView(v *View) {} func (i *InfoWindow) SetActive(b bool) {} func (i *InfoWindow) IsActive() bool { return true } -func (i *InfoWindow) GetMouseLoc(vloc buffer.Loc) buffer.Loc { +func (i *InfoWindow) LocFromVisual(vloc buffer.Loc) buffer.Loc { c := i.Buffer.GetActiveCursor() l := i.Buffer.LineBytes(0) n := utf8.RuneCountInString(i.Msg) diff --git a/internal/display/tabwindow.go b/internal/display/tabwindow.go index d3e9553b..3d25a42c 100644 --- a/internal/display/tabwindow.go +++ b/internal/display/tabwindow.go @@ -25,7 +25,7 @@ func NewTabWindow(w int, y int) *TabWindow { return tw } -func (w *TabWindow) GetMouseLoc(vloc buffer.Loc) int { +func (w *TabWindow) LocFromVisual(vloc buffer.Loc) int { x := -w.hscroll for i, n := range w.Names { diff --git a/internal/display/termwindow.go b/internal/display/termwindow.go index d195d532..95a90037 100644 --- a/internal/display/termwindow.go +++ b/internal/display/termwindow.go @@ -44,7 +44,7 @@ func (w *TermWindow) IsActive() bool { return w.active } -func (w *TermWindow) GetMouseLoc(vloc buffer.Loc) buffer.Loc { +func (w *TermWindow) LocFromVisual(vloc buffer.Loc) buffer.Loc { return vloc } diff --git a/internal/display/window.go b/internal/display/window.go index 4e39bdbd..bed538c5 100644 --- a/internal/display/window.go +++ b/internal/display/window.go @@ -20,7 +20,7 @@ type Window interface { Relocate() bool GetView() *View SetView(v *View) - GetMouseLoc(vloc buffer.Loc) buffer.Loc + LocFromVisual(vloc buffer.Loc) buffer.Loc Resize(w, h int) SetActive(b bool) IsActive() bool