mirror of
https://github.com/zyedidia/micro.git
synced 2026-02-27 17:30:37 +09:00
Working horizontal scrolling
This commit is contained in:
@@ -376,8 +376,8 @@ func DefaultBindings() map[string]string {
|
||||
"Backspace": "Backspace",
|
||||
"Alt-CtrlH": "DeleteWordLeft",
|
||||
"Alt-Backspace": "DeleteWordLeft",
|
||||
"Tab": "IndentSelection,InsertTab",
|
||||
"Backtab": "OutdentSelection,OutdentLine",
|
||||
"Tab": "InsertTab",
|
||||
"Backtab": "OutdentLine",
|
||||
"CtrlO": "OpenFile",
|
||||
"CtrlS": "Save",
|
||||
"CtrlF": "Find",
|
||||
|
||||
@@ -3,7 +3,6 @@ package buffer
|
||||
import (
|
||||
"unicode/utf8"
|
||||
|
||||
runewidth "github.com/mattn/go-runewidth"
|
||||
"github.com/zyedidia/clipboard"
|
||||
"github.com/zyedidia/micro/cmd/micro/util"
|
||||
)
|
||||
@@ -89,33 +88,7 @@ func (c *Cursor) GetVisualX() int {
|
||||
// 4 visual spaces)
|
||||
func (c *Cursor) GetCharPosInLine(b []byte, visualPos int) int {
|
||||
tabsize := int(c.buf.Settings["tabsize"].(float64))
|
||||
|
||||
// Scan rune by rune until we exceed the visual width that we are
|
||||
// looking for. Then we can return the character position we have found
|
||||
i := 0 // char pos
|
||||
width := 0 // string visual width
|
||||
for len(b) > 0 {
|
||||
r, size := utf8.DecodeRune(b)
|
||||
b = b[size:]
|
||||
|
||||
switch r {
|
||||
case '\t':
|
||||
ts := tabsize - (width % tabsize)
|
||||
width += ts
|
||||
default:
|
||||
width += runewidth.RuneWidth(r)
|
||||
}
|
||||
|
||||
if width >= visualPos {
|
||||
if width == visualPos {
|
||||
i++
|
||||
}
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
return i
|
||||
return util.GetCharPosInLine(b, visualPos, tabsize)
|
||||
}
|
||||
|
||||
// Start moves the cursor to the start of the line it is on
|
||||
|
||||
@@ -103,7 +103,8 @@ func (i *InfoWindow) displayBuffer() {
|
||||
vlocX := utf8.RuneCountInString(i.Msg)
|
||||
|
||||
tabsize := 4
|
||||
line, nColsBeforeStart := util.SliceVisualEnd(line, blocX, tabsize)
|
||||
line, nColsBeforeStart, bslice := util.SliceVisualEnd(line, blocX, tabsize)
|
||||
blocX = bslice
|
||||
|
||||
draw := func(r rune, style tcell.Style) {
|
||||
if nColsBeforeStart <= 0 {
|
||||
|
||||
@@ -13,9 +13,13 @@ import (
|
||||
)
|
||||
|
||||
type View struct {
|
||||
X, Y int // X,Y location of the view
|
||||
Width, Height int // Width and height of the view
|
||||
StartLine, StartCol int // Start line and start column of the view (vertical/horizontal scroll)
|
||||
X, Y int // X,Y location of the view
|
||||
Width, Height int // Width and height of the view
|
||||
|
||||
// Start line and start column of the view (vertical/horizontal scroll)
|
||||
// note that since the starting column of every line is different if the view
|
||||
// is scrolled, StartCol is a visual index (will be the same for every line)
|
||||
StartLine, StartCol int
|
||||
}
|
||||
|
||||
type Window interface {
|
||||
@@ -37,7 +41,8 @@ type BufWindow struct {
|
||||
|
||||
sline *StatusLine
|
||||
|
||||
lineHeight []int
|
||||
lineHeight []int
|
||||
gutterOffset int
|
||||
}
|
||||
|
||||
// NewBufWindow creates a new window at a location in the screen with a width and height
|
||||
@@ -60,6 +65,39 @@ func (v *View) SetView(view *View) {
|
||||
v = view
|
||||
}
|
||||
|
||||
func (w *BufWindow) getStartInfo(n, lineN int) ([]byte, int, int, *tcell.Style) {
|
||||
tabsize := util.IntOpt(w.Buf.Settings["tabsize"])
|
||||
width := 0
|
||||
bloc := buffer.Loc{0, lineN}
|
||||
b := w.Buf.LineBytes(lineN)
|
||||
curStyle := config.DefStyle
|
||||
var s *tcell.Style
|
||||
for len(b) > 0 {
|
||||
r, size := utf8.DecodeRune(b)
|
||||
|
||||
curStyle, found := w.getStyle(curStyle, bloc, r)
|
||||
if found {
|
||||
s = &curStyle
|
||||
}
|
||||
|
||||
w := 0
|
||||
switch r {
|
||||
case '\t':
|
||||
ts := tabsize - (width % tabsize)
|
||||
w = ts
|
||||
default:
|
||||
w = runewidth.RuneWidth(r)
|
||||
}
|
||||
if width+w > n {
|
||||
return b, n - width, bloc.X, s
|
||||
}
|
||||
width += w
|
||||
b = b[size:]
|
||||
bloc.X++
|
||||
}
|
||||
return b, n - width, bloc.X, s
|
||||
}
|
||||
|
||||
// Clear resets all cells in this window to the default style
|
||||
func (w *BufWindow) Clear() {
|
||||
for y := 0; y < w.Height; y++ {
|
||||
@@ -117,18 +155,18 @@ func (w *BufWindow) Relocate() bool {
|
||||
ret = true
|
||||
}
|
||||
|
||||
// TODO: horizontal scroll
|
||||
// if !b.Settings["softwrap"].(bool) {
|
||||
// cx := activeC.GetVisualX()
|
||||
// if cx < w.StartCol {
|
||||
// w.StartCol = cx
|
||||
// ret = true
|
||||
// }
|
||||
// if cx+v.lineNumOffset+1 > v.leftCol+v.Width {
|
||||
// v.leftCol = cx - v.Width + v.lineNumOffset + 1
|
||||
// ret = true
|
||||
// }
|
||||
// }
|
||||
// horizontal relocation (scrolling)
|
||||
if !b.Settings["softwrap"].(bool) {
|
||||
cx := activeC.GetVisualX()
|
||||
if cx < w.StartCol {
|
||||
w.StartCol = cx
|
||||
ret = true
|
||||
}
|
||||
if cx+w.gutterOffset+1 > w.StartCol+w.Width {
|
||||
w.StartCol = cx - w.Width + w.gutterOffset + 1
|
||||
ret = true
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
@@ -158,7 +196,7 @@ func (w *BufWindow) GetMouseLoc(svloc buffer.Loc) buffer.Loc {
|
||||
vloc := buffer.Loc{X: 0, Y: 0}
|
||||
|
||||
// this represents the current draw position in the buffer (char positions)
|
||||
bloc := buffer.Loc{X: w.StartCol, Y: w.StartLine}
|
||||
bloc := buffer.Loc{X: -1, Y: w.StartLine}
|
||||
|
||||
for vloc.Y = 0; vloc.Y < bufHeight; vloc.Y++ {
|
||||
vloc.X = 0
|
||||
@@ -166,12 +204,9 @@ func (w *BufWindow) GetMouseLoc(svloc buffer.Loc) buffer.Loc {
|
||||
vloc.X += maxLineNumLength + 1
|
||||
}
|
||||
|
||||
if svloc.X <= vloc.X && vloc.Y == svloc.Y {
|
||||
return bloc
|
||||
}
|
||||
|
||||
line := b.LineBytes(bloc.Y)
|
||||
line, nColsBeforeStart := util.SliceVisualEnd(line, bloc.X, tabsize)
|
||||
line, nColsBeforeStart, bslice := util.SliceVisualEnd(line, w.StartCol, tabsize)
|
||||
bloc.X = bslice
|
||||
|
||||
draw := func() {
|
||||
if nColsBeforeStart <= 0 {
|
||||
@@ -182,7 +217,11 @@ func (w *BufWindow) GetMouseLoc(svloc buffer.Loc) buffer.Loc {
|
||||
|
||||
w.lineHeight[vloc.Y] = bloc.Y
|
||||
|
||||
totalwidth := bloc.X - nColsBeforeStart
|
||||
totalwidth := w.StartCol - nColsBeforeStart
|
||||
|
||||
if svloc.X <= vloc.X && vloc.Y == svloc.Y {
|
||||
return bloc
|
||||
}
|
||||
for len(line) > 0 {
|
||||
if vloc.X == svloc.X && vloc.Y == svloc.Y {
|
||||
return bloc
|
||||
@@ -269,12 +308,12 @@ func (w *BufWindow) drawLineNum(lineNumStyle tcell.Style, softwrapped bool, maxL
|
||||
|
||||
// getStyle returns the highlight style for the given character position
|
||||
// If there is no change to the current highlight style it just returns that
|
||||
func (w *BufWindow) getStyle(style tcell.Style, bloc buffer.Loc, r rune) tcell.Style {
|
||||
func (w *BufWindow) getStyle(style tcell.Style, bloc buffer.Loc, r rune) (tcell.Style, bool) {
|
||||
if group, ok := w.Buf.Match(bloc.Y)[bloc.X]; ok {
|
||||
s := config.GetColor(group.String())
|
||||
return s
|
||||
return s, true
|
||||
}
|
||||
return style
|
||||
return style, false
|
||||
}
|
||||
|
||||
func (w *BufWindow) showCursor(x, y int, main bool) {
|
||||
@@ -329,7 +368,7 @@ func (w *BufWindow) displayBuffer() {
|
||||
vloc := buffer.Loc{X: 0, Y: 0}
|
||||
|
||||
// this represents the current draw position in the buffer (char positions)
|
||||
bloc := buffer.Loc{X: w.StartCol, Y: w.StartLine}
|
||||
bloc := buffer.Loc{X: -1, Y: w.StartLine}
|
||||
|
||||
activeC := b.GetActiveCursor()
|
||||
|
||||
@@ -344,8 +383,13 @@ func (w *BufWindow) displayBuffer() {
|
||||
w.drawLineNum(s, false, maxLineNumLength, &vloc, &bloc)
|
||||
}
|
||||
|
||||
line := b.LineBytes(bloc.Y)
|
||||
line, nColsBeforeStart := util.SliceVisualEnd(line, bloc.X, tabsize)
|
||||
w.gutterOffset = vloc.X
|
||||
|
||||
line, nColsBeforeStart, bslice, startStyle := w.getStartInfo(w.StartCol, bloc.Y)
|
||||
if startStyle != nil {
|
||||
curStyle = *startStyle
|
||||
}
|
||||
bloc.X = bslice
|
||||
|
||||
draw := func(r rune, style tcell.Style) {
|
||||
if nColsBeforeStart <= 0 {
|
||||
@@ -376,14 +420,14 @@ func (w *BufWindow) displayBuffer() {
|
||||
|
||||
w.lineHeight[vloc.Y] = bloc.Y
|
||||
|
||||
totalwidth := bloc.X - nColsBeforeStart
|
||||
totalwidth := w.StartCol - nColsBeforeStart
|
||||
for len(line) > 0 {
|
||||
if activeC.X == bloc.X && activeC.Y == bloc.Y {
|
||||
w.showCursor(vloc.X, vloc.Y, true)
|
||||
}
|
||||
|
||||
r, size := utf8.DecodeRune(line)
|
||||
curStyle = w.getStyle(curStyle, bloc, r)
|
||||
curStyle, _ = w.getStyle(curStyle, bloc, r)
|
||||
|
||||
draw(r, curStyle)
|
||||
|
||||
|
||||
@@ -54,8 +54,10 @@ func SliceStart(slc []byte, index int) []byte {
|
||||
// SliceVisualEnd will take a byte slice and slice off the start
|
||||
// up to a given visual index. If the index is in the middle of a
|
||||
// rune the number of visual columns into the rune will be returned
|
||||
func SliceVisualEnd(b []byte, n, tabsize int) ([]byte, int) {
|
||||
// It will also return the char pos of the first character of the slice
|
||||
func SliceVisualEnd(b []byte, n, tabsize int) ([]byte, int, int) {
|
||||
width := 0
|
||||
i := 0
|
||||
for len(b) > 0 {
|
||||
r, size := utf8.DecodeRune(b)
|
||||
|
||||
@@ -68,12 +70,13 @@ func SliceVisualEnd(b []byte, n, tabsize int) ([]byte, int) {
|
||||
w = runewidth.RuneWidth(r)
|
||||
}
|
||||
if width+w > n {
|
||||
return b, n - width
|
||||
return b, n - width, i
|
||||
}
|
||||
width += w
|
||||
b = b[size:]
|
||||
i++
|
||||
}
|
||||
return b, width
|
||||
return b, n - width, i
|
||||
}
|
||||
|
||||
// Abs is a simple absolute value function for ints
|
||||
@@ -87,6 +90,9 @@ func Abs(n int) int {
|
||||
// StringWidth returns the visual width of a byte array indexed from 0 to n (rune index)
|
||||
// with a given tabsize
|
||||
func StringWidth(b []byte, n, tabsize int) int {
|
||||
if n <= 0 {
|
||||
return 0
|
||||
}
|
||||
i := 0
|
||||
width := 0
|
||||
for len(b) > 0 {
|
||||
@@ -263,3 +269,36 @@ func GetLeadingWhitespace(b []byte) []byte {
|
||||
func IntOpt(opt interface{}) int {
|
||||
return int(opt.(float64))
|
||||
}
|
||||
|
||||
// GetCharPosInLine gets the char position of a visual x y
|
||||
// coordinate (this is necessary because tabs are 1 char but
|
||||
// 4 visual spaces)
|
||||
func GetCharPosInLine(b []byte, visualPos int, tabsize int) int {
|
||||
|
||||
// Scan rune by rune until we exceed the visual width that we are
|
||||
// looking for. Then we can return the character position we have found
|
||||
i := 0 // char pos
|
||||
width := 0 // string visual width
|
||||
for len(b) > 0 {
|
||||
r, size := utf8.DecodeRune(b)
|
||||
b = b[size:]
|
||||
|
||||
switch r {
|
||||
case '\t':
|
||||
ts := tabsize - (width % tabsize)
|
||||
width += ts
|
||||
default:
|
||||
width += runewidth.RuneWidth(r)
|
||||
}
|
||||
|
||||
if width >= visualPos {
|
||||
if width == visualPos {
|
||||
i++
|
||||
}
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user