Infobar prompts

This commit is contained in:
Zachary Yedidia
2018-12-31 23:47:24 -05:00
parent f79d45aafb
commit 90ae39322a
7 changed files with 170 additions and 15 deletions

View File

@@ -34,18 +34,18 @@ func (h *BufHandler) ScrollDown(n int) {
// MousePress is the event that should happen when a normal click happens
// This is almost always bound to left click
func (h *BufHandler) MousePress(e *tcell.EventMouse) bool {
h.ScrollUp(h.Buf.Settings["scrollspeed"].(int))
return false
}
// ScrollUpAction scrolls the view up
func (h *BufHandler) ScrollUpAction() bool {
h.ScrollUp(util.IntOpt(h.Buf.Settings["scrollspeed"]))
return false
}
// ScrollDownAction scrolls the view up
func (h *BufHandler) ScrollDownAction() bool {
h.ScrollDown(h.Buf.Settings["scrollspeed"].(int))
h.ScrollDown(util.IntOpt(h.Buf.Settings["scrollspeed"]))
return false
}
@@ -298,6 +298,38 @@ func (h *BufHandler) InsertSpace() bool {
// InsertNewline inserts a newline plus possible some whitespace if autoindent is on
func (h *BufHandler) InsertNewline() bool {
if h.Buf.Type == buffer.BTInfo {
info.MainBar.DonePrompt(false)
return false
}
// Insert a newline
if h.Cursor.HasSelection() {
h.Cursor.DeleteSelection()
h.Cursor.ResetSelection()
}
ws := util.GetLeadingWhitespace(h.Buf.LineBytes(h.Cursor.Y))
cx := h.Cursor.X
h.Buf.Insert(h.Cursor.Loc, "\n")
// h.Cursor.Right()
if h.Buf.Settings["autoindent"].(bool) {
if cx < len(ws) {
ws = ws[0:cx]
}
h.Buf.Insert(h.Cursor.Loc, string(ws))
// for i := 0; i < len(ws); i++ {
// h.Cursor.Right()
// }
// Remove the whitespaces if keepautoindent setting is off
if util.IsSpacesOrTabs(h.Buf.LineBytes(h.Cursor.Y-1)) && !h.Buf.Settings["keepautoindent"].(bool) {
line := h.Buf.LineBytes(h.Cursor.Y - 1)
h.Buf.Remove(buffer.Loc{X: 0, Y: h.Cursor.Y - 1}, buffer.Loc{X: utf8.RuneCount(line), Y: h.Cursor.Y - 1})
}
}
h.Cursor.LastVisualX = h.Cursor.GetVisualX()
return true
}
@@ -402,7 +434,7 @@ func (h *BufHandler) OutdentLine() bool {
return false
}
for x := 0; x < len(h.Buf.IndentString(h.Buf.Settings["tabsize"].(int))); x++ {
for x := 0; x < len(h.Buf.IndentString(util.IntOpt(h.Buf.Settings["tabsize"]))); x++ {
if len(util.GetLeadingWhitespace(h.Buf.LineBytes(h.Cursor.Y))) == 0 {
break
}
@@ -426,7 +458,7 @@ func (h *BufHandler) OutdentSelection() bool {
startY := start.Y
endY := end.Move(-1, h.Buf).Y
for y := startY; y <= endY; y++ {
for x := 0; x < len(h.Buf.IndentString(h.Buf.Settings["tabsize"].(int))); x++ {
for x := 0; x < len(h.Buf.IndentString(util.IntOpt(h.Buf.Settings["tabsize"]))); x++ {
if len(util.GetLeadingWhitespace(h.Buf.LineBytes(y))) == 0 {
break
}
@@ -442,7 +474,7 @@ func (h *BufHandler) OutdentSelection() bool {
// InsertTab inserts a tab or spaces
func (h *BufHandler) InsertTab() bool {
indent := h.Buf.IndentString(h.Buf.Settings["tabsize"].(int))
indent := h.Buf.IndentString(util.IntOpt(h.Buf.Settings["tabsize"]))
tabBytes := len(indent)
bytesUntilIndent := tabBytes - (h.Cursor.GetVisualX() % tabBytes)
h.Buf.Insert(h.Cursor.Loc, indent[:bytesUntilIndent])
@@ -609,6 +641,14 @@ func (h *BufHandler) SelectAll() bool {
// OpenFile opens a new file in the buffer
func (h *BufHandler) OpenFile() bool {
cb := func(resp string, canceled bool) {
if !canceled {
info.MainBar.Message("Opening", resp)
} else {
info.MainBar.Error("Canceled")
}
}
info.MainBar.Prompt("Open file: ", cb)
return false
}

View File

@@ -62,6 +62,7 @@ var (
BTLog = BufType{2, true, true, false}
BTScratch = BufType{3, false, true, false}
BTRaw = BufType{4, true, true, false}
BTInfo = BufType{5, false, true, false}
)
// Buffer stores the main information about a currently open file including

View File

@@ -1,12 +1,14 @@
package display
import (
"strings"
"unicode/utf8"
runewidth "github.com/mattn/go-runewidth"
"github.com/zyedidia/micro/cmd/micro/buffer"
"github.com/zyedidia/micro/cmd/micro/config"
"github.com/zyedidia/micro/cmd/micro/info"
"github.com/zyedidia/micro/cmd/micro/screen"
"github.com/zyedidia/micro/cmd/micro/util"
"github.com/zyedidia/tcell"
)
@@ -56,19 +58,99 @@ func (i *InfoWindow) Clear() {
}
}
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 := util.SliceVisualEnd(line, blocX, tabsize)
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)
}
}
func (i *InfoWindow) Display() {
x := 0
if i.HasPrompt || config.GlobalSettings["infobar"].(bool) {
if !i.HasPrompt && !i.HasMessage && !i.HasError {
return
}
style := i.defStyle
if i.HasError {
style = i.errStyle
}
display := i.Msg + strings.TrimSpace(string(i.Bytes()))
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()
}
}
}

View File

@@ -1,7 +1,6 @@
package display
import (
"log"
"strconv"
"unicode/utf8"
@@ -81,9 +80,8 @@ func (w *BufWindow) Bottomline() int {
// }
prev := 0
for i, l := range w.lineHeight {
for _, l := range w.lineHeight {
if l >= prev {
log.Println("lineHeight[", i, "] = ", l)
prev = l
} else {
break
@@ -98,7 +96,6 @@ func (w *BufWindow) Bottomline() int {
func (w *BufWindow) Relocate() bool {
b := w.Buf
height := w.Bottomline() + 1 - w.StartLine
log.Println("Height: ", height)
ret := false
activeC := w.Buf.GetActiveCursor()
cy := activeC.Y
@@ -115,7 +112,6 @@ func (w *BufWindow) Relocate() bool {
ret = true
} else if cy >= b.LinesNum()-scrollmargin && cy >= height {
w.StartLine = b.LinesNum() - height
log.Println(w.StartLine)
ret = true
}
@@ -217,7 +213,7 @@ func (w *BufWindow) displayBuffer() {
// this represents the current draw position in the buffer (char positions)
bloc := buffer.Loc{X: w.StartCol, Y: w.StartLine}
activeC := w.Buf.GetActiveCursor()
activeC := b.GetActiveCursor()
curStyle := config.DefStyle
for vloc.Y = 0; vloc.Y < bufHeight; vloc.Y++ {

View File

@@ -2,6 +2,7 @@ package info
import (
"fmt"
"strings"
"github.com/zyedidia/micro/cmd/micro/buffer"
)
@@ -30,13 +31,15 @@ type Bar struct {
// Is the current message a message from the gutter
GutterMessage bool
PromptCallback func(resp string, canceled bool)
}
func NewBar() *Bar {
ib := new(Bar)
ib.History = make(map[string][]string)
ib.Buffer = buffer.NewBufferFromString("", "infobar", buffer.BTScratch)
ib.Buffer = buffer.NewBufferFromString("", "infobar", buffer.BTInfo)
return ib
}
@@ -60,7 +63,23 @@ func (i *Bar) Error(msg ...interface{}) {
if i.HasPrompt == false {
// if there is no active prompt then style and display the message as normal
i.Msg = fmt.Sprint(msg...)
i.HasError = true
i.HasMessage, i.HasError = false, true
}
// TODO: add to log?
}
func (i *Bar) Prompt(msg string, callback func(string, bool)) {
i.Msg = msg
i.HasPrompt = true
i.HasMessage, i.HasError = false, false
i.PromptCallback = callback
}
func (i *Bar) DonePrompt(canceled bool) {
i.HasPrompt = false
if canceled {
i.PromptCallback("", true)
} else {
i.PromptCallback(strings.TrimSpace(string(i.LineBytes(0))), false)
}
}

View File

@@ -212,6 +212,7 @@ func main() {
for {
// Display everything
screen.Screen.Fill(' ', config.DefStyle)
screen.Screen.HideCursor()
ep.Display()
infowindow.Display()
screen.Screen.Show()

View File

@@ -155,6 +155,17 @@ func IsSpaces(str []byte) bool {
return true
}
// IsSpacesOrTabs checks if a given string contains only spaces and tabs
func IsSpacesOrTabs(str []byte) bool {
for _, c := range str {
if c != ' ' && c != '\t' {
return false
}
}
return true
}
// IsWhitespace returns true if the given rune is a space, tab, or newline
func IsWhitespace(c rune) bool {
return c == ' ' || c == '\t' || c == '\n'
@@ -247,3 +258,8 @@ func GetLeadingWhitespace(b []byte) []byte {
}
return ws
}
// IntOpt turns a float64 setting to an int
func IntOpt(opt interface{}) int {
return int(opt.(float64))
}