func (h *BufPane) ScrollAdjust() {
v := h.GetView()
end := h.SLocFromLoc(h.Buf.End())
- if h.Diff(v.StartLine, end) < v.Height-1 {
- v.StartLine = h.Scroll(end, -v.Height+1)
+ if h.Diff(v.StartLine, end) < h.BufHeight()-1 {
+ v.StartLine = h.Scroll(end, -h.BufHeight()+1)
}
h.SetView(v)
}
// Center centers the view on the cursor
func (h *BufPane) Center() bool {
v := h.GetView()
- v.StartLine = h.Scroll(h.SLocFromLoc(h.Cursor.Loc), -v.Height/2)
+ v.StartLine = h.Scroll(h.SLocFromLoc(h.Cursor.Loc), -h.BufHeight()/2)
h.SetView(v)
h.ScrollAdjust()
return true
// End moves the viewport to the end of the buffer
func (h *BufPane) End() bool {
v := h.GetView()
- v.StartLine = h.Scroll(h.SLocFromLoc(h.Buf.End()), -v.Height+1)
+ v.StartLine = h.Scroll(h.SLocFromLoc(h.Buf.End()), -h.BufHeight()+1)
h.SetView(v)
return true
}
// PageUp scrolls the view up a page
func (h *BufPane) PageUp() bool {
- v := h.GetView()
- h.ScrollUp(v.Height)
+ h.ScrollUp(h.BufHeight())
return true
}
// PageDown scrolls the view down a page
func (h *BufPane) PageDown() bool {
- v := h.GetView()
- h.ScrollDown(v.Height)
+ h.ScrollDown(h.BufHeight())
h.ScrollAdjust()
return true
}
if !h.Cursor.HasSelection() {
h.Cursor.OrigSelection[0] = h.Cursor.Loc
}
- h.Cursor.UpN(h.GetView().Height)
+ h.Cursor.UpN(h.BufHeight())
h.Cursor.SelectTo(h.Cursor.Loc)
h.Relocate()
return true
if !h.Cursor.HasSelection() {
h.Cursor.OrigSelection[0] = h.Cursor.Loc
}
- h.Cursor.DownN(h.GetView().Height)
+ h.Cursor.DownN(h.BufHeight())
h.Cursor.SelectTo(h.Cursor.Loc)
h.Relocate()
return true
h.Cursor.ResetSelection()
h.Cursor.StoreVisualX()
}
- h.Cursor.UpN(h.GetView().Height)
+ h.Cursor.UpN(h.BufHeight())
h.Relocate()
return true
}
h.Cursor.ResetSelection()
h.Cursor.StoreVisualX()
}
- h.Cursor.DownN(h.GetView().Height)
+ h.Cursor.DownN(h.BufHeight())
h.Relocate()
return true
}
// HalfPageUp scrolls the view up half a page
func (h *BufPane) HalfPageUp() bool {
- v := h.GetView()
- h.ScrollUp(v.Height / 2)
+ h.ScrollUp(h.BufHeight() / 2)
return true
}
// HalfPageDown scrolls the view down half a page
func (h *BufPane) HalfPageDown() bool {
- v := h.GetView()
- h.ScrollDown(v.Height / 2)
+ h.ScrollDown(h.BufHeight() / 2)
h.ScrollAdjust()
return true
}
sline *StatusLine
- gutterOffset int
- drawStatus bool
+ bufWidth int
+ bufHeight int
+ gutterOffset int
+ hasMessage bool
+ maxLineNumLength int
+ drawDivider bool
}
// NewBufWindow creates a new window at a location in the screen with a width and height
return w.active
}
+// BufWidth returns the width of the actual buffer displayed in the window,
+// which is usually less than the window width due to the gutter, ruler or scrollbar
+func (w *BufWindow) BufWidth() int {
+ return w.bufWidth
+}
+
+// BufHeight returns the height of the actual buffer displayed in the window,
+// which is usually less than the window height due to the statusline
+func (w *BufWindow) BufHeight() int {
+ return w.bufHeight
+}
+
+func (w *BufWindow) updateDisplayInfo() {
+ b := w.Buf
+
+ w.drawDivider = false
+ if !b.Settings["statusline"].(bool) {
+ _, h := screen.Screen.Size()
+ infoY := h
+ if config.GetGlobalOption("infobar").(bool) {
+ infoY--
+ }
+ if w.Y+w.Height != infoY {
+ w.drawDivider = true
+ }
+ }
+
+ w.bufHeight = w.Height
+ if b.Settings["statusline"].(bool) || w.drawDivider {
+ w.bufHeight--
+ }
+
+ w.hasMessage = len(b.Messages) > 0
+
+ // We need to know the string length of the largest line number
+ // so we can pad appropriately when displaying line numbers
+ w.maxLineNumLength = len(strconv.Itoa(b.LinesNum()))
+
+ w.gutterOffset = 0
+ if w.hasMessage {
+ w.gutterOffset += 2
+ }
+ if b.Settings["diffgutter"].(bool) {
+ w.gutterOffset++
+ }
+ if b.Settings["ruler"].(bool) {
+ w.gutterOffset += w.maxLineNumLength + 1
+ }
+
+ w.bufWidth = w.Width - w.gutterOffset
+ if w.Buf.Settings["scrollbar"].(bool) && w.Buf.LinesNum() > w.Height {
+ w.bufWidth--
+ }
+}
+
func (w *BufWindow) getStartInfo(n, lineN int) ([]byte, int, int, *tcell.Style) {
tabsize := util.IntOpt(w.Buf.Settings["tabsize"])
width := 0
// Returns true if the window location is moved
func (w *BufWindow) Relocate() bool {
b := w.Buf
- height := w.Height
- if w.drawStatus {
- height--
- }
+ height := w.bufHeight
ret := false
activeC := w.Buf.GetActiveCursor()
scrollmargin := int(b.Settings["scrollmargin"].(float64))
func (w *BufWindow) LocFromVisual(svloc buffer.Loc) buffer.Loc {
b := w.Buf
- hasMessage := len(b.Messages) > 0
- bufHeight := w.Height
- if w.drawStatus {
- bufHeight--
- }
-
- bufWidth := w.Width
- if w.Buf.Settings["scrollbar"].(bool) && w.Buf.LinesNum() > w.Height {
- bufWidth--
- }
-
- // We need to know the string length of the largest line number
- // so we can pad appropriately when displaying line numbers
- maxLineNumLength := len(strconv.Itoa(b.LinesNum()))
+ maxWidth := w.gutterOffset + w.bufWidth
tabsize := int(b.Settings["tabsize"].(float64))
softwrap := b.Settings["softwrap"].(bool)
// this represents the current draw position in the buffer (char positions)
bloc := buffer.Loc{X: -1, Y: w.StartLine.Line}
- for ; vloc.Y < bufHeight; vloc.Y++ {
- vloc.X = 0
- if hasMessage {
- vloc.X += 2
- }
- if b.Settings["diffgutter"].(bool) {
- vloc.X++
- }
- if b.Settings["ruler"].(bool) {
- vloc.X += maxLineNumLength + 1
- }
+ for ; vloc.Y < w.bufHeight; vloc.Y++ {
+ vloc.X = w.gutterOffset
line := b.LineBytes(bloc.Y)
line, nColsBeforeStart, bslice := util.SliceVisualEnd(line, w.StartCol, tabsize)
totalwidth += width
// If we reach the end of the window then we either stop or we wrap for softwrap
- if vloc.X >= bufWidth {
+ if vloc.X >= maxWidth {
if !softwrap {
break
} else {
vloc.Y++
- if vloc.Y >= bufHeight {
+ if vloc.Y >= w.bufHeight {
break
}
vloc.X = w.gutterOffset
return bloc
}
- if bloc.Y+1 >= b.LinesNum() || vloc.Y+1 >= bufHeight {
+ if bloc.Y+1 >= b.LinesNum() || vloc.Y+1 >= w.bufHeight {
return bloc
}
vloc.X++
}
-func (w *BufWindow) drawLineNum(lineNumStyle tcell.Style, softwrapped bool, maxLineNumLength int, vloc *buffer.Loc, bloc *buffer.Loc) {
+func (w *BufWindow) drawLineNum(lineNumStyle tcell.Style, softwrapped bool, vloc *buffer.Loc, bloc *buffer.Loc) {
cursorLine := w.Buf.GetActiveCursor().Loc.Y
var lineInt int
if w.Buf.Settings["relativeruler"] == false || cursorLine == bloc.Y {
lineNum := strconv.Itoa(util.Abs(lineInt))
// Write the spaces before the line number if necessary
- for i := 0; i < maxLineNumLength-len(lineNum); i++ {
+ for i := 0; i < w.maxLineNumLength-len(lineNum); i++ {
screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, ' ', nil, lineNumStyle)
vloc.X++
}
return
}
- hasMessage := len(b.Messages) > 0
- bufHeight := w.Height
- if w.drawStatus {
- bufHeight--
- }
-
- bufWidth := w.Width
- if w.Buf.Settings["scrollbar"].(bool) && w.Buf.LinesNum() > w.Height {
- bufWidth--
- }
+ maxWidth := w.gutterOffset + w.bufWidth
if b.ModifiedThisFrame {
if b.Settings["diffgutter"].(bool) {
}
}
- // We need to know the string length of the largest line number
- // so we can pad appropriately when displaying line numbers
- maxLineNumLength := len(strconv.Itoa(b.LinesNum()))
-
softwrap := b.Settings["softwrap"].(bool)
tabsize := util.IntOpt(b.Settings["tabsize"])
colorcolumn := util.IntOpt(b.Settings["colorcolumn"])
cursors := b.GetCursors()
curStyle := config.DefStyle
- for ; vloc.Y < bufHeight; vloc.Y++ {
+ for ; vloc.Y < w.bufHeight; vloc.Y++ {
vloc.X = 0
currentLine := false
}
if vloc.Y >= 0 {
- if hasMessage {
+ if w.hasMessage {
w.drawGutter(&vloc, &bloc)
}
}
if b.Settings["ruler"].(bool) {
- w.drawLineNum(s, false, maxLineNumLength, &vloc, &bloc)
+ w.drawLineNum(s, false, &vloc, &bloc)
}
} else {
- if hasMessage {
- vloc.X += 2
- }
- if b.Settings["diffgutter"].(bool) {
- vloc.X++
- }
- if b.Settings["ruler"].(bool) {
- vloc.X += maxLineNumLength + 1
- }
+ vloc.X = w.gutterOffset
}
- w.gutterOffset = vloc.X
-
line, nColsBeforeStart, bslice, startStyle := w.getStartInfo(w.StartCol, bloc.Y)
if startStyle != nil {
curStyle = *startStyle
totalwidth += width
// If we reach the end of the window then we either stop or we wrap for softwrap
- if vloc.X >= bufWidth {
+ if vloc.X >= maxWidth {
if !softwrap {
break
} else {
vloc.Y++
- if vloc.Y >= bufHeight {
+ if vloc.Y >= w.bufHeight {
break
}
vloc.X = 0
- if hasMessage {
+ if w.hasMessage {
w.drawGutter(&vloc, &bloc)
}
if b.Settings["diffgutter"].(bool) {
// This will draw an empty line number because the current line is wrapped
if b.Settings["ruler"].(bool) {
- w.drawLineNum(lineNumStyle, true, maxLineNumLength, &vloc, &bloc)
+ w.drawLineNum(lineNumStyle, true, &vloc, &bloc)
}
}
}
}
}
}
- for i := vloc.X; i < bufWidth; i++ {
+ for i := vloc.X; i < maxWidth; i++ {
curStyle := style
if s, ok := config.Colorscheme["color-column"]; ok {
if colorcolumn != 0 && i-w.gutterOffset+w.StartCol == colorcolumn {
screen.SetContent(i+w.X, vloc.Y+w.Y, ' ', nil, curStyle)
}
- if vloc.X != bufWidth {
+ if vloc.X != maxWidth {
// Display newline within a selection
draw(' ', nil, config.DefStyle, true)
}
}
func (w *BufWindow) displayStatusLine() {
- _, h := screen.Screen.Size()
- infoY := h
- if config.GetGlobalOption("infobar").(bool) {
- infoY--
- }
-
if w.Buf.Settings["statusline"].(bool) {
- w.drawStatus = true
w.sline.Display()
- } else if w.Y+w.Height != infoY {
- w.drawStatus = true
-
+ } else if w.drawDivider {
divchars := config.GetGlobalOption("divchars").(string)
if util.CharacterCountInString(divchars) != 2 {
divchars = "|-"
for x := w.X; x < w.X+w.Width; x++ {
screen.SetContent(x, w.Y+w.Height-1, divchar, combc, dividerStyle)
}
- } else {
- w.drawStatus = false
}
}
func (w *BufWindow) displayScrollBar() {
if w.Buf.Settings["scrollbar"].(bool) && w.Buf.LinesNum() > w.Height {
scrollX := w.X + w.Width - 1
- bufHeight := w.Height
- if w.drawStatus {
- bufHeight--
- }
barsize := int(float64(w.Height) / float64(w.Buf.LinesNum()) * float64(w.Height))
if barsize < 1 {
barsize = 1
scrollBarStyle = style
}
- for y := barstart; y < util.Min(barstart+barsize, w.Y+bufHeight); y++ {
+ for y := barstart; y < util.Min(barstart+barsize, w.Y+w.bufHeight); y++ {
screen.SetContent(scrollX, y, '|', nil, scrollBarStyle)
}
}
// Display displays the buffer and the statusline
func (w *BufWindow) Display() {
+ w.updateDisplayInfo()
+
w.displayStatusLine()
w.displayScrollBar()
w.displayBuffer()