mirror of
https://github.com/zyedidia/micro.git
synced 2026-03-29 22:27:13 +09:00
Change project layout and use go.mod
This commit is contained in:
585
internal/display/bufwindow.go
Normal file
585
internal/display/bufwindow.go
Normal file
@@ -0,0 +1,585 @@
|
||||
package display
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"unicode/utf8"
|
||||
|
||||
runewidth "github.com/mattn/go-runewidth"
|
||||
"github.com/zyedidia/micro/internal/buffer"
|
||||
"github.com/zyedidia/micro/internal/config"
|
||||
"github.com/zyedidia/micro/internal/screen"
|
||||
"github.com/zyedidia/micro/internal/util"
|
||||
"github.com/zyedidia/tcell"
|
||||
)
|
||||
|
||||
// The BufWindow provides a way of displaying a certain section
|
||||
// of a buffer
|
||||
type BufWindow struct {
|
||||
*View
|
||||
|
||||
// Buffer being shown in this window
|
||||
Buf *buffer.Buffer
|
||||
|
||||
active bool
|
||||
|
||||
sline *StatusLine
|
||||
|
||||
lineHeight []int
|
||||
hasCalcHeight bool
|
||||
gutterOffset int
|
||||
drawStatus bool
|
||||
}
|
||||
|
||||
// NewBufWindow creates a new window at a location in the screen with a width and height
|
||||
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)
|
||||
|
||||
return w
|
||||
}
|
||||
|
||||
func (w *BufWindow) SetBuffer(b *buffer.Buffer) {
|
||||
w.Buf = b
|
||||
}
|
||||
|
||||
func (v *View) GetView() *View {
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *View) SetView(view *View) {
|
||||
v = 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})
|
||||
}
|
||||
|
||||
func (w *BufWindow) SetActive(b bool) {
|
||||
w.active = b
|
||||
}
|
||||
|
||||
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++ {
|
||||
for x := 0; x < w.Width; x++ {
|
||||
screen.Screen.SetContent(w.X+x, w.Y+y, ' ', nil, config.DefStyle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bottomline returns the line number of the lowest line in the view
|
||||
// You might think that this is obviously just v.StartLine + v.Height
|
||||
// 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 {
|
||||
// b := w.Buf
|
||||
|
||||
// TODO: possible non-softwrap optimization
|
||||
// if !b.Settings["softwrap"].(bool) {
|
||||
// return w.StartLine + w.Height
|
||||
// }
|
||||
|
||||
prev := 0
|
||||
for _, l := range w.lineHeight {
|
||||
if l >= prev {
|
||||
prev = l
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return prev
|
||||
}
|
||||
|
||||
// Relocate moves the view window so that the cursor is in view
|
||||
// This is useful if the user has scrolled far away, and then starts typing
|
||||
// Returns true if the window location is moved
|
||||
func (w *BufWindow) Relocate() bool {
|
||||
b := w.Buf
|
||||
// how many buffer lines are in the view
|
||||
height := w.Bottomline() + 1 - w.StartLine
|
||||
h := w.Height
|
||||
if w.drawStatus {
|
||||
h--
|
||||
}
|
||||
if b.LinesNum() <= h || !w.hasCalcHeight {
|
||||
height = w.Height
|
||||
}
|
||||
ret := false
|
||||
activeC := w.Buf.GetActiveCursor()
|
||||
cy := activeC.Y
|
||||
scrollmargin := int(b.Settings["scrollmargin"].(float64))
|
||||
if cy < w.StartLine+scrollmargin && cy > scrollmargin-1 {
|
||||
w.StartLine = cy - scrollmargin
|
||||
ret = true
|
||||
} else if cy < w.StartLine {
|
||||
w.StartLine = cy
|
||||
ret = true
|
||||
}
|
||||
if cy > w.StartLine+height-1-scrollmargin && cy < b.LinesNum()-scrollmargin {
|
||||
w.StartLine = cy - height + 1 + scrollmargin
|
||||
ret = true
|
||||
} else if cy >= b.LinesNum()-scrollmargin && cy >= height {
|
||||
w.StartLine = b.LinesNum() - height
|
||||
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
|
||||
}
|
||||
|
||||
func (w *BufWindow) GetMouseLoc(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 {
|
||||
bufHeight--
|
||||
}
|
||||
|
||||
// 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()))
|
||||
|
||||
tabsize := int(b.Settings["tabsize"].(float64))
|
||||
softwrap := b.Settings["softwrap"].(bool)
|
||||
|
||||
// this represents the current draw position
|
||||
// within the current window
|
||||
vloc := buffer.Loc{X: 0, Y: 0}
|
||||
|
||||
// this represents the current draw position in the buffer (char positions)
|
||||
bloc := buffer.Loc{X: -1, Y: w.StartLine}
|
||||
|
||||
for vloc.Y = 0; vloc.Y < bufHeight; vloc.Y++ {
|
||||
vloc.X = 0
|
||||
if hasMessage {
|
||||
vloc.X += 2
|
||||
}
|
||||
if b.Settings["ruler"].(bool) {
|
||||
vloc.X += maxLineNumLength + 1
|
||||
}
|
||||
|
||||
line := b.LineBytes(bloc.Y)
|
||||
line, nColsBeforeStart, bslice := util.SliceVisualEnd(line, w.StartCol, tabsize)
|
||||
bloc.X = bslice
|
||||
|
||||
draw := func() {
|
||||
if nColsBeforeStart <= 0 {
|
||||
vloc.X++
|
||||
}
|
||||
nColsBeforeStart--
|
||||
}
|
||||
|
||||
totalwidth := w.StartCol - nColsBeforeStart
|
||||
|
||||
if svloc.X <= vloc.X+w.X && vloc.Y+w.Y == svloc.Y {
|
||||
return bloc
|
||||
}
|
||||
for len(line) > 0 {
|
||||
if vloc.X+w.X == svloc.X && vloc.Y+w.Y == svloc.Y {
|
||||
return bloc
|
||||
}
|
||||
|
||||
r, size := utf8.DecodeRune(line)
|
||||
draw()
|
||||
width := 0
|
||||
|
||||
switch r {
|
||||
case '\t':
|
||||
ts := tabsize - (totalwidth % tabsize)
|
||||
width = ts
|
||||
default:
|
||||
width = runewidth.RuneWidth(r)
|
||||
}
|
||||
|
||||
// Draw any extra characters either spaces for tabs or @ for incomplete wide runes
|
||||
if width > 1 {
|
||||
for i := 1; i < width; i++ {
|
||||
if vloc.X+w.X == svloc.X && vloc.Y+w.Y == svloc.Y {
|
||||
return bloc
|
||||
}
|
||||
draw()
|
||||
}
|
||||
}
|
||||
bloc.X++
|
||||
line = line[size:]
|
||||
|
||||
totalwidth += width
|
||||
|
||||
// If we reach the end of the window then we either stop or we wrap for softwrap
|
||||
if vloc.X >= w.Width {
|
||||
if !softwrap {
|
||||
break
|
||||
} else {
|
||||
vloc.Y++
|
||||
if vloc.Y >= bufHeight {
|
||||
break
|
||||
}
|
||||
vloc.X = 0
|
||||
// This will draw an empty line number because the current line is wrapped
|
||||
vloc.X += maxLineNumLength + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
if vloc.Y+w.Y == svloc.Y {
|
||||
return bloc
|
||||
}
|
||||
|
||||
bloc.X = w.StartCol
|
||||
bloc.Y++
|
||||
if bloc.Y >= b.LinesNum() {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.Loc{}
|
||||
}
|
||||
|
||||
func (w *BufWindow) drawGutter(vloc *buffer.Loc, bloc *buffer.Loc) {
|
||||
char := ' '
|
||||
s := config.DefStyle
|
||||
for _, m := range w.Buf.Messages {
|
||||
if m.Start.Y == bloc.Y || m.End.Y == bloc.Y {
|
||||
s = m.Style()
|
||||
char = '>'
|
||||
break
|
||||
}
|
||||
}
|
||||
screen.Screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, char, nil, s)
|
||||
vloc.X++
|
||||
screen.Screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, char, nil, s)
|
||||
vloc.X++
|
||||
}
|
||||
|
||||
func (w *BufWindow) drawLineNum(lineNumStyle tcell.Style, softwrapped bool, maxLineNumLength int, vloc *buffer.Loc, bloc *buffer.Loc) {
|
||||
lineNum := strconv.Itoa(bloc.Y + 1)
|
||||
|
||||
// Write the spaces before the line number if necessary
|
||||
for i := 0; i < maxLineNumLength-len(lineNum); i++ {
|
||||
screen.Screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, ' ', nil, lineNumStyle)
|
||||
vloc.X++
|
||||
}
|
||||
// Write the actual line number
|
||||
for _, ch := range lineNum {
|
||||
if softwrapped {
|
||||
screen.Screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, ' ', nil, lineNumStyle)
|
||||
} else {
|
||||
screen.Screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, ch, nil, lineNumStyle)
|
||||
}
|
||||
vloc.X++
|
||||
}
|
||||
|
||||
// Write the extra space
|
||||
screen.Screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, ' ', nil, lineNumStyle)
|
||||
vloc.X++
|
||||
}
|
||||
|
||||
// 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, bool) {
|
||||
if group, ok := w.Buf.Match(bloc.Y)[bloc.X]; ok {
|
||||
s := config.GetColor(group.String())
|
||||
return s, true
|
||||
}
|
||||
return style, false
|
||||
}
|
||||
|
||||
func (w *BufWindow) showCursor(x, y int, main bool) {
|
||||
if w.active {
|
||||
if main {
|
||||
screen.Screen.ShowCursor(x, y)
|
||||
} else {
|
||||
r, _, _, _ := screen.Screen.GetContent(x, y)
|
||||
screen.Screen.SetContent(x, y, r, nil, config.DefStyle.Reverse(true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// displayBuffer draws the buffer being shown in this window on the screen.Screen
|
||||
func (w *BufWindow) displayBuffer() {
|
||||
b := w.Buf
|
||||
|
||||
hasMessage := len(b.Messages) > 0
|
||||
bufHeight := w.Height
|
||||
if w.drawStatus {
|
||||
bufHeight--
|
||||
}
|
||||
|
||||
w.hasCalcHeight = true
|
||||
start := w.StartLine
|
||||
if b.Settings["syntax"].(bool) && b.SyntaxDef != nil {
|
||||
if start > 0 && b.Rehighlight(start-1) {
|
||||
b.Highlighter.ReHighlightLine(b, start-1)
|
||||
b.SetRehighlight(start-1, false)
|
||||
}
|
||||
|
||||
b.Highlighter.ReHighlightStates(b, start)
|
||||
|
||||
b.Highlighter.HighlightMatches(b, w.StartLine, w.StartLine+bufHeight)
|
||||
}
|
||||
|
||||
lineNumStyle := config.DefStyle
|
||||
if style, ok := config.Colorscheme["line-number"]; ok {
|
||||
lineNumStyle = style
|
||||
}
|
||||
curNumStyle := config.DefStyle
|
||||
if style, ok := config.Colorscheme["current-line-number"]; ok {
|
||||
curNumStyle = style
|
||||
}
|
||||
|
||||
// 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"])
|
||||
|
||||
// this represents the current draw position
|
||||
// within the current window
|
||||
vloc := buffer.Loc{X: 0, Y: 0}
|
||||
|
||||
// this represents the current draw position in the buffer (char positions)
|
||||
bloc := buffer.Loc{X: -1, Y: w.StartLine}
|
||||
|
||||
cursors := b.GetCursors()
|
||||
|
||||
curStyle := config.DefStyle
|
||||
for vloc.Y = 0; vloc.Y < bufHeight; vloc.Y++ {
|
||||
vloc.X = 0
|
||||
|
||||
if hasMessage {
|
||||
w.drawGutter(&vloc, &bloc)
|
||||
}
|
||||
|
||||
if b.Settings["ruler"].(bool) {
|
||||
s := lineNumStyle
|
||||
for _, c := range cursors {
|
||||
if bloc.Y == c.Y && w.active {
|
||||
s = curNumStyle
|
||||
break
|
||||
}
|
||||
}
|
||||
w.drawLineNum(s, false, maxLineNumLength, &vloc, &bloc)
|
||||
}
|
||||
|
||||
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, showcursor bool) {
|
||||
if nColsBeforeStart <= 0 {
|
||||
for _, c := range cursors {
|
||||
if c.HasSelection() &&
|
||||
(bloc.GreaterEqual(c.CurSelection[0]) && bloc.LessThan(c.CurSelection[1]) ||
|
||||
bloc.LessThan(c.CurSelection[0]) && bloc.GreaterEqual(c.CurSelection[1])) {
|
||||
// The current character is selected
|
||||
style = config.DefStyle.Reverse(true)
|
||||
|
||||
if s, ok := config.Colorscheme["selection"]; ok {
|
||||
style = s
|
||||
}
|
||||
}
|
||||
|
||||
if b.Settings["cursorline"].(bool) && w.active &&
|
||||
!c.HasSelection() && c.Y == bloc.Y {
|
||||
if s, ok := config.Colorscheme["cursor-line"]; ok {
|
||||
fg, _, _ := s.Decompose()
|
||||
style = style.Background(fg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if s, ok := config.Colorscheme["color-column"]; ok {
|
||||
if colorcolumn != 0 && vloc.X-w.gutterOffset == colorcolumn {
|
||||
fg, _, _ := s.Decompose()
|
||||
style = style.Background(fg)
|
||||
}
|
||||
}
|
||||
|
||||
screen.Screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, r, nil, style)
|
||||
|
||||
if showcursor {
|
||||
for _, c := range cursors {
|
||||
if c.X == bloc.X && c.Y == bloc.Y && !c.HasSelection() {
|
||||
w.showCursor(w.X+vloc.X, w.Y+vloc.Y, c.Num == 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
vloc.X++
|
||||
}
|
||||
nColsBeforeStart--
|
||||
}
|
||||
|
||||
w.lineHeight[vloc.Y] = bloc.Y
|
||||
|
||||
totalwidth := w.StartCol - nColsBeforeStart
|
||||
for len(line) > 0 {
|
||||
r, size := utf8.DecodeRune(line)
|
||||
curStyle, _ = w.getStyle(curStyle, bloc, r)
|
||||
|
||||
draw(r, curStyle, true)
|
||||
|
||||
width := 0
|
||||
|
||||
char := ' '
|
||||
switch r {
|
||||
case '\t':
|
||||
ts := tabsize - (totalwidth % tabsize)
|
||||
width = ts
|
||||
default:
|
||||
width = runewidth.RuneWidth(r)
|
||||
char = '@'
|
||||
}
|
||||
|
||||
// Draw any extra characters either spaces for tabs or @ for incomplete wide runes
|
||||
if width > 1 {
|
||||
for i := 1; i < width; i++ {
|
||||
draw(char, curStyle, false)
|
||||
}
|
||||
}
|
||||
bloc.X++
|
||||
line = line[size:]
|
||||
|
||||
totalwidth += width
|
||||
|
||||
// If we reach the end of the window then we either stop or we wrap for softwrap
|
||||
if vloc.X >= w.Width {
|
||||
if !softwrap {
|
||||
break
|
||||
} else {
|
||||
vloc.Y++
|
||||
if vloc.Y >= bufHeight {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
style := config.DefStyle
|
||||
for _, c := range cursors {
|
||||
if b.Settings["cursorline"].(bool) && w.active &&
|
||||
!c.HasSelection() && c.Y == bloc.Y {
|
||||
if s, ok := config.Colorscheme["cursor-line"]; ok {
|
||||
fg, _, _ := s.Decompose()
|
||||
style = style.Background(fg)
|
||||
}
|
||||
}
|
||||
}
|
||||
for i := vloc.X; i < w.Width; i++ {
|
||||
curStyle := style
|
||||
if s, ok := config.Colorscheme["color-column"]; ok {
|
||||
if colorcolumn != 0 && i-w.gutterOffset == colorcolumn {
|
||||
fg, _, _ := s.Decompose()
|
||||
curStyle = style.Background(fg)
|
||||
}
|
||||
}
|
||||
screen.Screen.SetContent(i+w.X, vloc.Y+w.Y, ' ', nil, curStyle)
|
||||
}
|
||||
|
||||
for _, c := range cursors {
|
||||
if c.X == bloc.X && c.Y == bloc.Y && !c.HasSelection() {
|
||||
w.showCursor(w.X+vloc.X, w.Y+vloc.Y, c.Num == 0)
|
||||
}
|
||||
}
|
||||
|
||||
bloc.X = w.StartCol
|
||||
bloc.Y++
|
||||
if bloc.Y >= b.LinesNum() {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
for x := w.X; x < w.X+w.Width; x++ {
|
||||
screen.Screen.SetContent(x, w.Y+w.Height-1, '-', nil, config.DefStyle.Reverse(true))
|
||||
}
|
||||
} else {
|
||||
w.drawStatus = false
|
||||
}
|
||||
}
|
||||
|
||||
// Display displays the buffer and the statusline
|
||||
func (w *BufWindow) Display() {
|
||||
w.displayStatusLine()
|
||||
w.displayBuffer()
|
||||
}
|
||||
227
internal/display/infowindow.go
Normal file
227
internal/display/infowindow.go
Normal file
@@ -0,0 +1,227 @@
|
||||
package display
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
|
||||
runewidth "github.com/mattn/go-runewidth"
|
||||
"github.com/zyedidia/micro/internal/buffer"
|
||||
"github.com/zyedidia/micro/internal/config"
|
||||
"github.com/zyedidia/micro/internal/info"
|
||||
"github.com/zyedidia/micro/internal/screen"
|
||||
"github.com/zyedidia/micro/internal/util"
|
||||
"github.com/zyedidia/tcell"
|
||||
)
|
||||
|
||||
type InfoWindow struct {
|
||||
*info.InfoBuf
|
||||
*View
|
||||
|
||||
defStyle tcell.Style
|
||||
errStyle tcell.Style
|
||||
}
|
||||
|
||||
func NewInfoWindow(b *info.InfoBuf) *InfoWindow {
|
||||
iw := new(InfoWindow)
|
||||
iw.InfoBuf = b
|
||||
iw.View = new(View)
|
||||
|
||||
iw.defStyle = config.DefStyle
|
||||
|
||||
if _, ok := config.Colorscheme["message"]; ok {
|
||||
iw.defStyle = config.Colorscheme["message"]
|
||||
}
|
||||
|
||||
iw.errStyle = config.DefStyle.
|
||||
Foreground(tcell.ColorBlack).
|
||||
Background(tcell.ColorMaroon)
|
||||
|
||||
if _, ok := config.Colorscheme["error-message"]; ok {
|
||||
iw.errStyle = config.Colorscheme["error-message"]
|
||||
}
|
||||
|
||||
iw.Width, iw.Y = screen.Screen.Size()
|
||||
iw.Y--
|
||||
|
||||
return iw
|
||||
}
|
||||
|
||||
func (i *InfoWindow) Resize(w, h int) {
|
||||
i.Width = w
|
||||
i.Y = h
|
||||
}
|
||||
|
||||
func (i *InfoWindow) SetBuffer(b *buffer.Buffer) {
|
||||
i.InfoBuf.Buffer = b
|
||||
}
|
||||
|
||||
func (i *InfoWindow) Relocate() bool { return false }
|
||||
func (i *InfoWindow) GetView() *View { return i.View }
|
||||
func (i *InfoWindow) SetView(v *View) {}
|
||||
func (i *InfoWindow) SetActive(b bool) {}
|
||||
|
||||
func (i *InfoWindow) GetMouseLoc(vloc buffer.Loc) buffer.Loc {
|
||||
c := i.Buffer.GetActiveCursor()
|
||||
l := i.Buffer.LineBytes(0)
|
||||
n := utf8.RuneCountInString(i.Msg)
|
||||
return buffer.Loc{c.GetCharPosInLine(l, vloc.X-n), 0}
|
||||
}
|
||||
|
||||
func (i *InfoWindow) Clear() {
|
||||
for x := 0; x < i.Width; x++ {
|
||||
screen.Screen.SetContent(x, i.Y, ' ', nil, config.DefStyle)
|
||||
}
|
||||
}
|
||||
|
||||
func (i *InfoWindow) displayBuffer() {
|
||||
b := i.Buffer
|
||||
line := b.LineBytes(0)
|
||||
activeC := b.GetActiveCursor()
|
||||
|
||||
blocX := 0
|
||||
vlocX := utf8.RuneCountInString(i.Msg)
|
||||
|
||||
tabsize := 4
|
||||
line, nColsBeforeStart, bslice := util.SliceVisualEnd(line, blocX, tabsize)
|
||||
blocX = bslice
|
||||
|
||||
draw := func(r rune, style tcell.Style) {
|
||||
if nColsBeforeStart <= 0 {
|
||||
bloc := buffer.Loc{X: blocX, Y: 0}
|
||||
if activeC.HasSelection() &&
|
||||
(bloc.GreaterEqual(activeC.CurSelection[0]) && bloc.LessThan(activeC.CurSelection[1]) ||
|
||||
bloc.LessThan(activeC.CurSelection[0]) && bloc.GreaterEqual(activeC.CurSelection[1])) {
|
||||
// The current character is selected
|
||||
style = config.DefStyle.Reverse(true)
|
||||
|
||||
if s, ok := config.Colorscheme["selection"]; ok {
|
||||
style = s
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
screen.Screen.SetContent(vlocX, i.Y, r, nil, style)
|
||||
vlocX++
|
||||
}
|
||||
nColsBeforeStart--
|
||||
}
|
||||
|
||||
totalwidth := blocX - nColsBeforeStart
|
||||
for len(line) > 0 {
|
||||
if activeC.X == blocX {
|
||||
screen.Screen.ShowCursor(vlocX, i.Y)
|
||||
}
|
||||
|
||||
r, size := utf8.DecodeRune(line)
|
||||
|
||||
draw(r, i.defStyle)
|
||||
|
||||
width := 0
|
||||
|
||||
char := ' '
|
||||
switch r {
|
||||
case '\t':
|
||||
ts := tabsize - (totalwidth % tabsize)
|
||||
width = ts
|
||||
default:
|
||||
width = runewidth.RuneWidth(r)
|
||||
char = '@'
|
||||
}
|
||||
|
||||
blocX++
|
||||
line = line[size:]
|
||||
|
||||
// Draw any extra characters either spaces for tabs or @ for incomplete wide runes
|
||||
if width > 1 {
|
||||
for j := 1; j < width; j++ {
|
||||
draw(char, i.defStyle)
|
||||
}
|
||||
}
|
||||
totalwidth += width
|
||||
if vlocX >= i.Width {
|
||||
break
|
||||
}
|
||||
}
|
||||
if activeC.X == blocX {
|
||||
screen.Screen.ShowCursor(vlocX, i.Y)
|
||||
}
|
||||
}
|
||||
|
||||
var keydisplay = []string{"^Q Quit, ^S Save, ^O Open, ^G Help, ^E Command Bar, ^K Cut Line", "^F Find, ^Z Undo, ^Y Redo, ^A Select All, ^D Duplicate Line, ^T New Tab"}
|
||||
|
||||
func (i *InfoWindow) displayKeyMenu() {
|
||||
// TODO: maybe make this based on the actual keybindings
|
||||
|
||||
for y := 0; y < len(keydisplay); y++ {
|
||||
for x := 0; x < i.Width; x++ {
|
||||
if x < len(keydisplay[y]) {
|
||||
screen.Screen.SetContent(x, i.Y-len(keydisplay)+y, rune(keydisplay[y][x]), nil, config.DefStyle)
|
||||
} else {
|
||||
screen.Screen.SetContent(x, i.Y-len(keydisplay)+y, ' ', nil, config.DefStyle)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (i *InfoWindow) Display() {
|
||||
x := 0
|
||||
if config.GetGlobalOption("keymenu").(bool) {
|
||||
i.displayKeyMenu()
|
||||
}
|
||||
|
||||
if i.HasPrompt || config.GlobalSettings["infobar"].(bool) {
|
||||
if !i.HasPrompt && !i.HasMessage && !i.HasError {
|
||||
return
|
||||
}
|
||||
i.Clear()
|
||||
style := i.defStyle
|
||||
|
||||
if i.HasError {
|
||||
style = i.errStyle
|
||||
}
|
||||
|
||||
display := i.Msg
|
||||
for _, c := range display {
|
||||
screen.Screen.SetContent(x, i.Y, c, nil, style)
|
||||
x += runewidth.RuneWidth(c)
|
||||
}
|
||||
|
||||
if i.HasPrompt {
|
||||
i.displayBuffer()
|
||||
}
|
||||
}
|
||||
|
||||
if i.HasSuggestions && len(i.Suggestions) > 1 {
|
||||
statusLineStyle := config.DefStyle.Reverse(true)
|
||||
if style, ok := config.Colorscheme["statusline"]; ok {
|
||||
statusLineStyle = style
|
||||
}
|
||||
keymenuOffset := 0
|
||||
if config.GetGlobalOption("keymenu").(bool) {
|
||||
keymenuOffset = len(keydisplay)
|
||||
}
|
||||
x := 0
|
||||
for j, s := range i.Suggestions {
|
||||
style := statusLineStyle
|
||||
if i.CurSuggestion == j {
|
||||
style = style.Reverse(true)
|
||||
}
|
||||
for _, r := range s {
|
||||
screen.Screen.SetContent(x, i.Y-keymenuOffset-1, r, nil, style)
|
||||
x++
|
||||
if x >= i.Width {
|
||||
return
|
||||
}
|
||||
}
|
||||
screen.Screen.SetContent(x, i.Y-keymenuOffset-1, ' ', nil, statusLineStyle)
|
||||
x++
|
||||
if x >= i.Width {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for x < i.Width {
|
||||
screen.Screen.SetContent(x, i.Y-keymenuOffset-1, ' ', nil, statusLineStyle)
|
||||
x++
|
||||
}
|
||||
}
|
||||
}
|
||||
120
internal/display/statusline.go
Normal file
120
internal/display/statusline.go
Normal file
@@ -0,0 +1,120 @@
|
||||
package display
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"path"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/zyedidia/micro/internal/buffer"
|
||||
"github.com/zyedidia/micro/internal/config"
|
||||
"github.com/zyedidia/micro/internal/screen"
|
||||
)
|
||||
|
||||
// StatusLine represents the information line at the bottom
|
||||
// of each window
|
||||
// It gives information such as filename, whether the file has been
|
||||
// modified, filetype, cursor location
|
||||
type StatusLine struct {
|
||||
FormatLeft string
|
||||
FormatRight string
|
||||
Info map[string]func(*buffer.Buffer) string
|
||||
|
||||
win *BufWindow
|
||||
}
|
||||
|
||||
// TODO: plugin modify status line formatter
|
||||
|
||||
// NewStatusLine returns a statusline bound to a window
|
||||
func NewStatusLine(win *BufWindow) *StatusLine {
|
||||
s := new(StatusLine)
|
||||
s.FormatLeft = "$(filename) $(modified)($(line),$(col)) $(opt:filetype) $(opt:fileformat) $(opt:encoding)"
|
||||
// s.FormatLeft = "$(filename) $(modified)(line,col) $(opt:filetype) $(opt:fileformat)"
|
||||
s.FormatRight = "$(bind:ToggleKeyMenu): show bindings, $(bind:ToggleHelp): toggle help"
|
||||
s.Info = map[string]func(*buffer.Buffer) string{
|
||||
"filename": func(b *buffer.Buffer) string {
|
||||
if b.Settings["basename"].(bool) {
|
||||
return path.Base(b.GetName())
|
||||
}
|
||||
return b.GetName()
|
||||
},
|
||||
"line": func(b *buffer.Buffer) string {
|
||||
return strconv.Itoa(b.GetActiveCursor().Y + 1)
|
||||
},
|
||||
"col": func(b *buffer.Buffer) string {
|
||||
return strconv.Itoa(b.GetActiveCursor().X + 1)
|
||||
},
|
||||
"modified": func(b *buffer.Buffer) string {
|
||||
if b.Modified() {
|
||||
return "+ "
|
||||
}
|
||||
return ""
|
||||
},
|
||||
}
|
||||
s.win = win
|
||||
return s
|
||||
}
|
||||
|
||||
// FindOpt finds a given option in the current buffer's settings
|
||||
func (s *StatusLine) FindOpt(opt string) interface{} {
|
||||
if val, ok := s.win.Buf.Settings[opt]; ok {
|
||||
return val
|
||||
}
|
||||
return "null"
|
||||
}
|
||||
|
||||
var formatParser = regexp.MustCompile(`\$\(.+?\)`)
|
||||
|
||||
// Display draws the statusline to the screen
|
||||
func (s *StatusLine) Display() {
|
||||
// We'll draw the line at the lowest line in the window
|
||||
y := s.win.Height + s.win.Y - 1
|
||||
|
||||
formatter := func(match []byte) []byte {
|
||||
name := match[2 : len(match)-1]
|
||||
if bytes.HasPrefix(name, []byte("opt")) {
|
||||
option := name[4:]
|
||||
return []byte(fmt.Sprint(s.FindOpt(string(option))))
|
||||
} else if bytes.HasPrefix(name, []byte("bind")) {
|
||||
binding := string(name[5:])
|
||||
for k, v := range config.Bindings {
|
||||
if v == binding {
|
||||
return []byte(k)
|
||||
}
|
||||
}
|
||||
return []byte("null")
|
||||
} else {
|
||||
return []byte(s.Info[string(name)](s.win.Buf))
|
||||
}
|
||||
}
|
||||
|
||||
leftText := []byte(s.FormatLeft)
|
||||
leftText = formatParser.ReplaceAllFunc([]byte(s.FormatLeft), formatter)
|
||||
rightText := []byte(s.FormatRight)
|
||||
rightText = formatParser.ReplaceAllFunc([]byte(s.FormatRight), formatter)
|
||||
|
||||
statusLineStyle := config.DefStyle.Reverse(true)
|
||||
if style, ok := config.Colorscheme["statusline"]; ok {
|
||||
statusLineStyle = style
|
||||
}
|
||||
|
||||
leftLen := utf8.RuneCount(leftText)
|
||||
rightLen := utf8.RuneCount(rightText)
|
||||
|
||||
winX := s.win.X
|
||||
for x := 0; x < s.win.Width; x++ {
|
||||
if x < leftLen {
|
||||
r, size := utf8.DecodeRune(leftText)
|
||||
leftText = leftText[size:]
|
||||
screen.Screen.SetContent(winX+x, y, r, nil, statusLineStyle)
|
||||
} else if x >= s.win.Width-rightLen && x < rightLen+s.win.Width-rightLen {
|
||||
r, size := utf8.DecodeRune(rightText)
|
||||
rightText = rightText[size:]
|
||||
screen.Screen.SetContent(winX+x, y, r, nil, statusLineStyle)
|
||||
} else {
|
||||
screen.Screen.SetContent(winX+x, y, ' ', nil, statusLineStyle)
|
||||
}
|
||||
}
|
||||
}
|
||||
127
internal/display/tabwindow.go
Normal file
127
internal/display/tabwindow.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package display
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/zyedidia/micro/internal/buffer"
|
||||
"github.com/zyedidia/micro/internal/config"
|
||||
"github.com/zyedidia/micro/internal/screen"
|
||||
"github.com/zyedidia/micro/internal/util"
|
||||
)
|
||||
|
||||
type TabWindow struct {
|
||||
Names []string
|
||||
active int
|
||||
Y int
|
||||
width int
|
||||
hscroll int
|
||||
}
|
||||
|
||||
func NewTabWindow(w int, y int) *TabWindow {
|
||||
tw := new(TabWindow)
|
||||
tw.width = w
|
||||
tw.Y = y
|
||||
return tw
|
||||
}
|
||||
|
||||
func (w *TabWindow) GetMouseLoc(vloc buffer.Loc) int {
|
||||
x := -w.hscroll
|
||||
|
||||
for i, n := range w.Names {
|
||||
x++
|
||||
s := utf8.RuneCountInString(n)
|
||||
if vloc.Y == w.Y && vloc.X < x+s {
|
||||
return i
|
||||
}
|
||||
x += s
|
||||
x += 3
|
||||
if x >= w.width {
|
||||
break
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (w *TabWindow) Scroll(amt int) {
|
||||
w.hscroll += amt
|
||||
w.hscroll = util.Clamp(w.hscroll, 0, w.TotalSize()-w.width)
|
||||
}
|
||||
|
||||
func (w *TabWindow) TotalSize() int {
|
||||
sum := 2
|
||||
for _, n := range w.Names {
|
||||
sum += utf8.RuneCountInString(n) + 4
|
||||
}
|
||||
return sum - 4
|
||||
}
|
||||
|
||||
func (w *TabWindow) Active() int {
|
||||
return w.active
|
||||
}
|
||||
|
||||
func (w *TabWindow) SetActive(a int) {
|
||||
w.active = a
|
||||
x := 2
|
||||
s := w.TotalSize()
|
||||
for i, n := range w.Names {
|
||||
c := utf8.RuneCountInString(n)
|
||||
if i == a {
|
||||
if x+c >= w.hscroll+w.width {
|
||||
w.hscroll = util.Clamp(x+c+1-w.width, 0, s-w.width)
|
||||
} else if x < w.hscroll {
|
||||
w.hscroll = util.Clamp(x-4, 0, s-w.width)
|
||||
}
|
||||
break
|
||||
}
|
||||
x += c + 4
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: handle files with character width >=2
|
||||
|
||||
func (w *TabWindow) Display() {
|
||||
x := -w.hscroll
|
||||
done := false
|
||||
|
||||
draw := func(r rune, n int) {
|
||||
for i := 0; i < n; i++ {
|
||||
if x == w.width-1 && !done {
|
||||
screen.Screen.SetContent(w.width-1, w.Y, '>', nil, config.DefStyle.Reverse(true))
|
||||
x++
|
||||
break
|
||||
} else if x == 0 && w.hscroll > 0 {
|
||||
screen.Screen.SetContent(0, w.Y, '<', nil, config.DefStyle.Reverse(true))
|
||||
} else if x >= 0 && x < w.width {
|
||||
screen.Screen.SetContent(x, w.Y, r, nil, config.DefStyle.Reverse(true))
|
||||
}
|
||||
x++
|
||||
}
|
||||
}
|
||||
|
||||
for i, n := range w.Names {
|
||||
if i == w.active {
|
||||
draw('[', 1)
|
||||
} else {
|
||||
draw(' ', 1)
|
||||
}
|
||||
for _, c := range n {
|
||||
draw(c, 1)
|
||||
}
|
||||
if i == len(w.Names)-1 {
|
||||
done = true
|
||||
}
|
||||
if i == w.active {
|
||||
draw(']', 1)
|
||||
draw(' ', 2)
|
||||
} else {
|
||||
draw(' ', 3)
|
||||
}
|
||||
if x >= w.width {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if x < w.width {
|
||||
draw(' ', w.width-x)
|
||||
}
|
||||
}
|
||||
112
internal/display/termwindow.go
Normal file
112
internal/display/termwindow.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package display
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/zyedidia/micro/internal/buffer"
|
||||
"github.com/zyedidia/micro/internal/config"
|
||||
"github.com/zyedidia/micro/internal/screen"
|
||||
"github.com/zyedidia/micro/internal/shell"
|
||||
"github.com/zyedidia/tcell"
|
||||
"github.com/zyedidia/terminal"
|
||||
)
|
||||
|
||||
type TermWindow struct {
|
||||
*View
|
||||
*shell.Terminal
|
||||
|
||||
active bool
|
||||
}
|
||||
|
||||
func NewTermWindow(x, y, w, h int, term *shell.Terminal) *TermWindow {
|
||||
tw := new(TermWindow)
|
||||
tw.View = new(View)
|
||||
tw.Terminal = term
|
||||
tw.X, tw.Y = x, y
|
||||
tw.Resize(w, h)
|
||||
return tw
|
||||
}
|
||||
|
||||
// Resize informs the terminal of a resize event
|
||||
func (w *TermWindow) Resize(width, height int) {
|
||||
if config.GetGlobalOption("statusline").(bool) {
|
||||
height--
|
||||
}
|
||||
w.Term.Resize(width, height)
|
||||
w.Width, w.Height = width, height
|
||||
}
|
||||
|
||||
func (w *TermWindow) SetActive(b bool) {
|
||||
w.active = b
|
||||
}
|
||||
|
||||
func (w *TermWindow) GetMouseLoc(vloc buffer.Loc) buffer.Loc {
|
||||
return vloc
|
||||
}
|
||||
|
||||
func (w *TermWindow) Clear() {
|
||||
for y := 0; y < w.Height; y++ {
|
||||
for x := 0; x < w.Width; x++ {
|
||||
screen.Screen.SetContent(w.X+x, w.Y+y, ' ', nil, config.DefStyle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *TermWindow) Relocate() bool { return true }
|
||||
func (w *TermWindow) GetView() *View {
|
||||
return w.View
|
||||
}
|
||||
func (w *TermWindow) SetView(v *View) {
|
||||
w.View = v
|
||||
}
|
||||
|
||||
// Display displays this terminal in a view
|
||||
func (w *TermWindow) Display() {
|
||||
w.State.Lock()
|
||||
defer w.State.Unlock()
|
||||
|
||||
var l buffer.Loc
|
||||
for y := 0; y < w.Height; y++ {
|
||||
for x := 0; x < w.Width; x++ {
|
||||
l.X, l.Y = x, y
|
||||
c, f, b := w.State.Cell(x, y)
|
||||
|
||||
fg, bg := int(f), int(b)
|
||||
if f == terminal.DefaultFG {
|
||||
fg = int(tcell.ColorDefault)
|
||||
}
|
||||
if b == terminal.DefaultBG {
|
||||
bg = int(tcell.ColorDefault)
|
||||
}
|
||||
st := tcell.StyleDefault.Foreground(config.GetColor256(int(fg))).Background(config.GetColor256(int(bg)))
|
||||
|
||||
if l.LessThan(w.Selection[1]) && l.GreaterEqual(w.Selection[0]) || l.LessThan(w.Selection[0]) && l.GreaterEqual(w.Selection[1]) {
|
||||
st = st.Reverse(true)
|
||||
}
|
||||
|
||||
screen.Screen.SetContent(w.X+x, w.Y+y, c, nil, st)
|
||||
}
|
||||
}
|
||||
if config.GetGlobalOption("statusline").(bool) {
|
||||
statusLineStyle := config.DefStyle.Reverse(true)
|
||||
if style, ok := config.Colorscheme["statusline"]; ok {
|
||||
statusLineStyle = style
|
||||
}
|
||||
|
||||
text := []byte(w.Name())
|
||||
textLen := utf8.RuneCount(text)
|
||||
for x := 0; x < w.Width; x++ {
|
||||
if x < textLen {
|
||||
r, size := utf8.DecodeRune(text)
|
||||
text = text[size:]
|
||||
screen.Screen.SetContent(w.X+x, w.Y+w.Height, r, nil, statusLineStyle)
|
||||
} else {
|
||||
screen.Screen.SetContent(w.X+x, w.Y+w.Height, ' ', nil, statusLineStyle)
|
||||
}
|
||||
}
|
||||
}
|
||||
if w.State.CursorVisible() && w.active {
|
||||
curx, cury := w.State.Cursor()
|
||||
screen.Screen.ShowCursor(curx+w.X, cury+w.Y)
|
||||
}
|
||||
}
|
||||
74
internal/display/uiwindow.go
Normal file
74
internal/display/uiwindow.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package display
|
||||
|
||||
import (
|
||||
"github.com/zyedidia/micro/internal/buffer"
|
||||
"github.com/zyedidia/micro/internal/config"
|
||||
"github.com/zyedidia/micro/internal/screen"
|
||||
"github.com/zyedidia/micro/internal/views"
|
||||
)
|
||||
|
||||
type UIWindow struct {
|
||||
root *views.Node
|
||||
}
|
||||
|
||||
func NewUIWindow(n *views.Node) *UIWindow {
|
||||
uw := new(UIWindow)
|
||||
uw.root = n
|
||||
return uw
|
||||
}
|
||||
|
||||
func (w *UIWindow) drawNode(n *views.Node) {
|
||||
cs := n.Children()
|
||||
dividerStyle := config.DefStyle
|
||||
if style, ok := config.Colorscheme["divider"]; ok {
|
||||
dividerStyle = style
|
||||
}
|
||||
|
||||
for i, c := range cs {
|
||||
if c.IsLeaf() && c.Kind == views.STVert {
|
||||
if i != len(cs)-1 {
|
||||
for h := 0; h < c.H; h++ {
|
||||
screen.Screen.SetContent(c.X+c.W, c.Y+h, '|', nil, dividerStyle.Reverse(true))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
w.drawNode(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *UIWindow) Display() {
|
||||
w.drawNode(w.root)
|
||||
}
|
||||
|
||||
func (w *UIWindow) GetMouseSplitID(vloc buffer.Loc) uint64 {
|
||||
var mouseLoc func(*views.Node) uint64
|
||||
mouseLoc = func(n *views.Node) uint64 {
|
||||
cs := n.Children()
|
||||
for i, c := range cs {
|
||||
if c.Kind == views.STVert {
|
||||
if i != len(cs)-1 {
|
||||
if vloc.X == c.X+c.W && vloc.Y >= c.Y && vloc.Y < c.Y+c.H {
|
||||
return c.ID()
|
||||
}
|
||||
}
|
||||
} else if c.Kind == views.STHoriz {
|
||||
if i != len(cs)-1 {
|
||||
if vloc.Y == c.Y+c.H-1 && vloc.X >= c.X && vloc.X < c.X+c.W {
|
||||
return c.ID()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, c := range cs {
|
||||
m := mouseLoc(c)
|
||||
if m != 0 {
|
||||
return m
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
return mouseLoc(w.root)
|
||||
}
|
||||
func (w *UIWindow) Resize(width, height int) {}
|
||||
func (w *UIWindow) SetActive(b bool) {}
|
||||
31
internal/display/window.go
Normal file
31
internal/display/window.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package display
|
||||
|
||||
import (
|
||||
"github.com/zyedidia/micro/internal/buffer"
|
||||
)
|
||||
|
||||
type View struct {
|
||||
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 {
|
||||
Display()
|
||||
Clear()
|
||||
Relocate() bool
|
||||
GetView() *View
|
||||
SetView(v *View)
|
||||
GetMouseLoc(vloc buffer.Loc) buffer.Loc
|
||||
Resize(w, h int)
|
||||
SetActive(b bool)
|
||||
}
|
||||
|
||||
type BWindow interface {
|
||||
Window
|
||||
SetBuffer(b *buffer.Buffer)
|
||||
}
|
||||
Reference in New Issue
Block a user