mirror of
https://github.com/zyedidia/micro.git
synced 2026-03-16 05:47:06 +09:00
Start terminal emulator
This commit is contained in:
@@ -17,19 +17,19 @@ import (
|
|||||||
|
|
||||||
// ScrollUp is not an action
|
// ScrollUp is not an action
|
||||||
func (h *BufHandler) ScrollUp(n int) {
|
func (h *BufHandler) ScrollUp(n int) {
|
||||||
v := h.Win.GetView()
|
v := h.GetView()
|
||||||
if v.StartLine >= n {
|
if v.StartLine >= n {
|
||||||
v.StartLine -= n
|
v.StartLine -= n
|
||||||
h.Win.SetView(v)
|
h.SetView(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScrollDown is not an action
|
// ScrollDown is not an action
|
||||||
func (h *BufHandler) ScrollDown(n int) {
|
func (h *BufHandler) ScrollDown(n int) {
|
||||||
v := h.Win.GetView()
|
v := h.GetView()
|
||||||
if v.StartLine <= h.Buf.LinesNum()-1-n {
|
if v.StartLine <= h.Buf.LinesNum()-1-n {
|
||||||
v.StartLine += n
|
v.StartLine += n
|
||||||
h.Win.SetView(v)
|
h.SetView(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,12 +38,12 @@ func (h *BufHandler) ScrollDown(n int) {
|
|||||||
func (h *BufHandler) MousePress(e *tcell.EventMouse) bool {
|
func (h *BufHandler) MousePress(e *tcell.EventMouse) bool {
|
||||||
b := h.Buf
|
b := h.Buf
|
||||||
mx, my := e.Position()
|
mx, my := e.Position()
|
||||||
mouseLoc := h.Win.GetMouseLoc(buffer.Loc{mx, my})
|
mouseLoc := h.GetMouseLoc(buffer.Loc{mx, my})
|
||||||
h.Cursor.Loc = mouseLoc
|
h.Cursor.Loc = mouseLoc
|
||||||
if h.mouseReleased {
|
if h.mouseReleased {
|
||||||
if b.NumCursors() > 1 {
|
if b.NumCursors() > 1 {
|
||||||
b.ClearCursors()
|
b.ClearCursors()
|
||||||
h.Win.Relocate()
|
h.Relocate()
|
||||||
}
|
}
|
||||||
if time.Since(h.lastClickTime)/time.Millisecond < config.DoubleClickThreshold && (mouseLoc.X == h.lastLoc.X && mouseLoc.Y == h.lastLoc.Y) {
|
if time.Since(h.lastClickTime)/time.Millisecond < config.DoubleClickThreshold && (mouseLoc.X == h.lastLoc.X && mouseLoc.Y == h.lastLoc.Y) {
|
||||||
if h.doubleClick {
|
if h.doubleClick {
|
||||||
@@ -104,7 +104,7 @@ func (h *BufHandler) ScrollDownAction() bool {
|
|||||||
|
|
||||||
// Center centers the view on the cursor
|
// Center centers the view on the cursor
|
||||||
func (h *BufHandler) Center() bool {
|
func (h *BufHandler) Center() bool {
|
||||||
v := h.Win.GetView()
|
v := h.GetView()
|
||||||
v.StartLine = h.Cursor.Y - v.Height/2
|
v.StartLine = h.Cursor.Y - v.Height/2
|
||||||
if v.StartLine+v.Height > h.Buf.LinesNum() {
|
if v.StartLine+v.Height > h.Buf.LinesNum() {
|
||||||
v.StartLine = h.Buf.LinesNum() - v.Height
|
v.StartLine = h.Buf.LinesNum() - v.Height
|
||||||
@@ -112,7 +112,7 @@ func (h *BufHandler) Center() bool {
|
|||||||
if v.StartLine < 0 {
|
if v.StartLine < 0 {
|
||||||
v.StartLine = 0
|
v.StartLine = 0
|
||||||
}
|
}
|
||||||
h.Win.SetView(v)
|
h.SetView(v)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -826,19 +826,19 @@ func (h *BufHandler) OpenFile() bool {
|
|||||||
|
|
||||||
// Start moves the viewport to the start of the buffer
|
// Start moves the viewport to the start of the buffer
|
||||||
func (h *BufHandler) Start() bool {
|
func (h *BufHandler) Start() bool {
|
||||||
v := h.Win.GetView()
|
v := h.GetView()
|
||||||
v.StartLine = 0
|
v.StartLine = 0
|
||||||
h.Win.SetView(v)
|
h.SetView(v)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// End moves the viewport to the end of the buffer
|
// End moves the viewport to the end of the buffer
|
||||||
func (h *BufHandler) End() bool {
|
func (h *BufHandler) End() bool {
|
||||||
// TODO: softwrap problems?
|
// TODO: softwrap problems?
|
||||||
v := h.Win.GetView()
|
v := h.GetView()
|
||||||
if v.Height > h.Buf.LinesNum() {
|
if v.Height > h.Buf.LinesNum() {
|
||||||
v.StartLine = 0
|
v.StartLine = 0
|
||||||
h.Win.SetView(v)
|
h.SetView(v)
|
||||||
} else {
|
} else {
|
||||||
h.StartLine = h.Buf.LinesNum() - v.Height
|
h.StartLine = h.Buf.LinesNum() - v.Height
|
||||||
}
|
}
|
||||||
@@ -847,19 +847,19 @@ func (h *BufHandler) End() bool {
|
|||||||
|
|
||||||
// PageUp scrolls the view up a page
|
// PageUp scrolls the view up a page
|
||||||
func (h *BufHandler) PageUp() bool {
|
func (h *BufHandler) PageUp() bool {
|
||||||
v := h.Win.GetView()
|
v := h.GetView()
|
||||||
if v.StartLine > v.Height {
|
if v.StartLine > v.Height {
|
||||||
h.ScrollUp(v.Height)
|
h.ScrollUp(v.Height)
|
||||||
} else {
|
} else {
|
||||||
v.StartLine = 0
|
v.StartLine = 0
|
||||||
}
|
}
|
||||||
h.Win.SetView(v)
|
h.SetView(v)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// PageDown scrolls the view down a page
|
// PageDown scrolls the view down a page
|
||||||
func (h *BufHandler) PageDown() bool {
|
func (h *BufHandler) PageDown() bool {
|
||||||
v := h.Win.GetView()
|
v := h.GetView()
|
||||||
if h.Buf.LinesNum()-(v.StartLine+v.Height) > v.Height {
|
if h.Buf.LinesNum()-(v.StartLine+v.Height) > v.Height {
|
||||||
h.ScrollDown(v.Height)
|
h.ScrollDown(v.Height)
|
||||||
} else if h.Buf.LinesNum() >= v.Height {
|
} else if h.Buf.LinesNum() >= v.Height {
|
||||||
@@ -873,7 +873,7 @@ func (h *BufHandler) SelectPageUp() bool {
|
|||||||
if !h.Cursor.HasSelection() {
|
if !h.Cursor.HasSelection() {
|
||||||
h.Cursor.OrigSelection[0] = h.Cursor.Loc
|
h.Cursor.OrigSelection[0] = h.Cursor.Loc
|
||||||
}
|
}
|
||||||
h.Cursor.UpN(h.Win.GetView().Height)
|
h.Cursor.UpN(h.GetView().Height)
|
||||||
h.Cursor.SelectTo(h.Cursor.Loc)
|
h.Cursor.SelectTo(h.Cursor.Loc)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -883,7 +883,7 @@ func (h *BufHandler) SelectPageDown() bool {
|
|||||||
if !h.Cursor.HasSelection() {
|
if !h.Cursor.HasSelection() {
|
||||||
h.Cursor.OrigSelection[0] = h.Cursor.Loc
|
h.Cursor.OrigSelection[0] = h.Cursor.Loc
|
||||||
}
|
}
|
||||||
h.Cursor.DownN(h.Win.GetView().Height)
|
h.Cursor.DownN(h.GetView().Height)
|
||||||
h.Cursor.SelectTo(h.Cursor.Loc)
|
h.Cursor.SelectTo(h.Cursor.Loc)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -897,7 +897,7 @@ func (h *BufHandler) CursorPageUp() bool {
|
|||||||
h.Cursor.ResetSelection()
|
h.Cursor.ResetSelection()
|
||||||
h.Cursor.StoreVisualX()
|
h.Cursor.StoreVisualX()
|
||||||
}
|
}
|
||||||
h.Cursor.UpN(h.Win.GetView().Height)
|
h.Cursor.UpN(h.GetView().Height)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -910,25 +910,25 @@ func (h *BufHandler) CursorPageDown() bool {
|
|||||||
h.Cursor.ResetSelection()
|
h.Cursor.ResetSelection()
|
||||||
h.Cursor.StoreVisualX()
|
h.Cursor.StoreVisualX()
|
||||||
}
|
}
|
||||||
h.Cursor.DownN(h.Win.GetView().Height)
|
h.Cursor.DownN(h.GetView().Height)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// HalfPageUp scrolls the view up half a page
|
// HalfPageUp scrolls the view up half a page
|
||||||
func (h *BufHandler) HalfPageUp() bool {
|
func (h *BufHandler) HalfPageUp() bool {
|
||||||
v := h.Win.GetView()
|
v := h.GetView()
|
||||||
if v.StartLine > v.Height/2 {
|
if v.StartLine > v.Height/2 {
|
||||||
h.ScrollUp(v.Height / 2)
|
h.ScrollUp(v.Height / 2)
|
||||||
} else {
|
} else {
|
||||||
v.StartLine = 0
|
v.StartLine = 0
|
||||||
}
|
}
|
||||||
h.Win.SetView(v)
|
h.SetView(v)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// HalfPageDown scrolls the view down half a page
|
// HalfPageDown scrolls the view down half a page
|
||||||
func (h *BufHandler) HalfPageDown() bool {
|
func (h *BufHandler) HalfPageDown() bool {
|
||||||
v := h.Win.GetView()
|
v := h.GetView()
|
||||||
if h.Buf.LinesNum()-(v.StartLine+v.Height) > v.Height/2 {
|
if h.Buf.LinesNum()-(v.StartLine+v.Height) > v.Height/2 {
|
||||||
h.ScrollDown(v.Height / 2)
|
h.ScrollDown(v.Height / 2)
|
||||||
} else {
|
} else {
|
||||||
@@ -936,7 +936,7 @@ func (h *BufHandler) HalfPageDown() bool {
|
|||||||
v.StartLine = h.Buf.LinesNum() - v.Height
|
v.StartLine = h.Buf.LinesNum() - v.Height
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
h.Win.SetView(v)
|
h.SetView(v)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1193,7 +1193,7 @@ func (h *BufHandler) SpawnMultiCursorSelect() bool {
|
|||||||
func (h *BufHandler) MouseMultiCursor(e *tcell.EventMouse) bool {
|
func (h *BufHandler) MouseMultiCursor(e *tcell.EventMouse) bool {
|
||||||
b := h.Buf
|
b := h.Buf
|
||||||
mx, my := e.Position()
|
mx, my := e.Position()
|
||||||
mouseLoc := h.Win.GetMouseLoc(buffer.Loc{X: mx, Y: my})
|
mouseLoc := h.GetMouseLoc(buffer.Loc{X: mx, Y: my})
|
||||||
c := buffer.NewCursor(b, mouseLoc)
|
c := buffer.NewCursor(b, mouseLoc)
|
||||||
b.AddCursor(c)
|
b.AddCursor(c)
|
||||||
b.MergeCursors()
|
b.MergeCursors()
|
||||||
@@ -1219,7 +1219,7 @@ func (h *BufHandler) SkipMultiCursor() bool {
|
|||||||
lastC.Loc = lastC.CurSelection[1]
|
lastC.Loc = lastC.CurSelection[1]
|
||||||
|
|
||||||
h.Buf.MergeCursors()
|
h.Buf.MergeCursors()
|
||||||
h.Win.Relocate()
|
h.Relocate()
|
||||||
} else {
|
} else {
|
||||||
InfoBar.Message("No matches found")
|
InfoBar.Message("No matches found")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,8 +52,9 @@ func BufMapMouse(k MouseEvent, action string) {
|
|||||||
// The ActionHandler can access the window for necessary info about
|
// The ActionHandler can access the window for necessary info about
|
||||||
// visual positions for mouse clicks and scrolling
|
// visual positions for mouse clicks and scrolling
|
||||||
type BufHandler struct {
|
type BufHandler struct {
|
||||||
|
display.Window
|
||||||
|
|
||||||
Buf *buffer.Buffer
|
Buf *buffer.Buffer
|
||||||
Win display.Window
|
|
||||||
|
|
||||||
cursors []*buffer.Cursor
|
cursors []*buffer.Cursor
|
||||||
Cursor *buffer.Cursor // the active cursor
|
Cursor *buffer.Cursor // the active cursor
|
||||||
@@ -100,7 +101,7 @@ type BufHandler struct {
|
|||||||
func NewBufHandler(buf *buffer.Buffer, win display.Window) *BufHandler {
|
func NewBufHandler(buf *buffer.Buffer, win display.Window) *BufHandler {
|
||||||
h := new(BufHandler)
|
h := new(BufHandler)
|
||||||
h.Buf = buf
|
h.Buf = buf
|
||||||
h.Win = win
|
h.Window = win
|
||||||
|
|
||||||
h.cursors = []*buffer.Cursor{buffer.NewCursor(buf, buf.StartCursor)}
|
h.cursors = []*buffer.Cursor{buffer.NewCursor(buf, buf.StartCursor)}
|
||||||
h.Cursor = h.cursors[0]
|
h.Cursor = h.cursors[0]
|
||||||
@@ -133,7 +134,7 @@ func (h *BufHandler) HandleEvent(event tcell.Event) {
|
|||||||
// Mouse was just released
|
// Mouse was just released
|
||||||
|
|
||||||
mx, my := e.Position()
|
mx, my := e.Position()
|
||||||
mouseLoc := h.Win.GetMouseLoc(buffer.Loc{X: mx, Y: my})
|
mouseLoc := h.GetMouseLoc(buffer.Loc{X: mx, Y: my})
|
||||||
|
|
||||||
// Relocating here isn't really necessary because the cursor will
|
// Relocating here isn't really necessary because the cursor will
|
||||||
// be in the right place from the last mouse event
|
// be in the right place from the last mouse event
|
||||||
@@ -171,14 +172,14 @@ func (h *BufHandler) DoKeyEvent(e KeyEvent) bool {
|
|||||||
h.Buf.SetCurCursor(c.Num)
|
h.Buf.SetCurCursor(c.Num)
|
||||||
h.Cursor = c
|
h.Cursor = c
|
||||||
if action(h) {
|
if action(h) {
|
||||||
h.Win.Relocate()
|
h.Relocate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if action(h) {
|
if action(h) {
|
||||||
h.Win.Relocate()
|
h.Relocate()
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -190,7 +191,7 @@ func (h *BufHandler) DoKeyEvent(e KeyEvent) bool {
|
|||||||
func (h *BufHandler) DoMouseEvent(e MouseEvent, te *tcell.EventMouse) bool {
|
func (h *BufHandler) DoMouseEvent(e MouseEvent, te *tcell.EventMouse) bool {
|
||||||
if action, ok := BufMouseBindings[e]; ok {
|
if action, ok := BufMouseBindings[e]; ok {
|
||||||
if action(h, te) {
|
if action(h, te) {
|
||||||
h.Win.Relocate()
|
h.Relocate()
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,12 @@ import (
|
|||||||
"github.com/zyedidia/micro/cmd/micro/views"
|
"github.com/zyedidia/micro/cmd/micro/views"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Pane interface {
|
||||||
|
Handler
|
||||||
|
display.Window
|
||||||
|
ID() uint64
|
||||||
|
}
|
||||||
|
|
||||||
type EditPane struct {
|
type EditPane struct {
|
||||||
display.Window
|
display.Window
|
||||||
*BufHandler
|
*BufHandler
|
||||||
|
|||||||
@@ -37,7 +37,5 @@ type MouseAction func(Handler, tcell.EventMouse) bool
|
|||||||
// A Handler will take a tcell event and execute it
|
// A Handler will take a tcell event and execute it
|
||||||
// appropriately
|
// appropriately
|
||||||
type Handler interface {
|
type Handler interface {
|
||||||
// DoKeyEvent(KeyEvent) bool
|
|
||||||
// DoMouseEvent(MouseEvent, *tcell.EventMouse) (MouseAction, bool)
|
|
||||||
HandleEvent(tcell.Event)
|
HandleEvent(tcell.Event)
|
||||||
}
|
}
|
||||||
|
|||||||
66
cmd/micro/action/termhandler.go
Normal file
66
cmd/micro/action/termhandler.go
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
package action
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/zyedidia/clipboard"
|
||||||
|
"github.com/zyedidia/micro/cmd/micro/display"
|
||||||
|
"github.com/zyedidia/micro/cmd/micro/shell"
|
||||||
|
"github.com/zyedidia/tcell"
|
||||||
|
"github.com/zyedidia/terminal"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TermHandler struct {
|
||||||
|
*shell.Terminal
|
||||||
|
display.Window
|
||||||
|
|
||||||
|
mouseReleased bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleEvent handles a tcell event by forwarding it to the terminal emulator
|
||||||
|
// If the event is a mouse event and the program running in the emulator
|
||||||
|
// does not have mouse support, the emulator will support selections and
|
||||||
|
// copy-paste
|
||||||
|
func (t *TermHandler) HandleEvent(event tcell.Event) {
|
||||||
|
if e, ok := event.(*tcell.EventKey); ok {
|
||||||
|
if t.Status == shell.TTDone {
|
||||||
|
switch e.Key() {
|
||||||
|
case tcell.KeyEscape, tcell.KeyCtrlQ, tcell.KeyEnter:
|
||||||
|
t.Close()
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if e.Key() == tcell.KeyCtrlC && t.HasSelection() {
|
||||||
|
clipboard.WriteAll(t.GetSelection(t.GetView().Width), "clipboard")
|
||||||
|
InfoBar.Message("Copied selection to clipboard")
|
||||||
|
} else if t.Status != shell.TTDone {
|
||||||
|
t.WriteString(event.EscSeq())
|
||||||
|
}
|
||||||
|
} else if e, ok := event.(*tcell.EventMouse); !ok || t.State.Mode(terminal.ModeMouseMask) {
|
||||||
|
t.WriteString(event.EscSeq())
|
||||||
|
} else {
|
||||||
|
x, y := e.Position()
|
||||||
|
v := t.GetView()
|
||||||
|
x -= v.X
|
||||||
|
y += v.Y
|
||||||
|
|
||||||
|
if e.Buttons() == tcell.Button1 {
|
||||||
|
if !t.mouseReleased {
|
||||||
|
// drag
|
||||||
|
t.Selection[1].X = x
|
||||||
|
t.Selection[1].Y = y
|
||||||
|
} else {
|
||||||
|
t.Selection[0].X = x
|
||||||
|
t.Selection[0].Y = y
|
||||||
|
t.Selection[1].X = x
|
||||||
|
t.Selection[1].Y = y
|
||||||
|
}
|
||||||
|
|
||||||
|
t.mouseReleased = false
|
||||||
|
} else if e.Buttons() == tcell.ButtonNone {
|
||||||
|
if !t.mouseReleased {
|
||||||
|
t.Selection[1].X = x
|
||||||
|
t.Selection[1].Y = y
|
||||||
|
}
|
||||||
|
t.mouseReleased = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
87
cmd/micro/display/termwindow.go
Normal file
87
cmd/micro/display/termwindow.go
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
package display
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/zyedidia/micro/cmd/micro/buffer"
|
||||||
|
"github.com/zyedidia/micro/cmd/micro/config"
|
||||||
|
"github.com/zyedidia/micro/cmd/micro/screen"
|
||||||
|
"github.com/zyedidia/micro/cmd/micro/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.Terminal = term
|
||||||
|
tw.X, tw.Y = x, y
|
||||||
|
tw.Width, tw.Height = w, h
|
||||||
|
return tw
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resize informs the terminal of a resize event
|
||||||
|
func (w *TermWindow) Resize(width, height int) {
|
||||||
|
w.Term.Resize(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 w.State.CursorVisible() && w.active {
|
||||||
|
curx, cury := w.State.Cursor()
|
||||||
|
screen.Screen.ShowCursor(curx+w.X, cury+w.Y)
|
||||||
|
}
|
||||||
|
}
|
||||||
127
cmd/micro/shell/terminal.go
Normal file
127
cmd/micro/shell/terminal.go
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
package shell
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/zyedidia/micro/cmd/micro/buffer"
|
||||||
|
"github.com/zyedidia/micro/cmd/micro/screen"
|
||||||
|
"github.com/zyedidia/terminal"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TermType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
TTIdle = iota // Waiting for a new command
|
||||||
|
TTRunning // Currently running a command
|
||||||
|
TTDone // Finished running a command
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Terminal holds information for the terminal emulator
|
||||||
|
type Terminal struct {
|
||||||
|
State terminal.State
|
||||||
|
Term *terminal.VT
|
||||||
|
title string
|
||||||
|
Status TermType
|
||||||
|
Selection [2]buffer.Loc
|
||||||
|
wait bool
|
||||||
|
getOutput bool
|
||||||
|
output *bytes.Buffer
|
||||||
|
callback string
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasSelection returns whether this terminal has a valid selection
|
||||||
|
func (t *Terminal) HasSelection() bool {
|
||||||
|
return t.Selection[0] != t.Selection[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSelection returns the selected text
|
||||||
|
func (t *Terminal) GetSelection(width int) string {
|
||||||
|
start := t.Selection[0]
|
||||||
|
end := t.Selection[1]
|
||||||
|
if start.GreaterThan(end) {
|
||||||
|
start, end = end, start
|
||||||
|
}
|
||||||
|
var ret string
|
||||||
|
var l buffer.Loc
|
||||||
|
for y := start.Y; y <= end.Y; y++ {
|
||||||
|
for x := 0; x < width; x++ {
|
||||||
|
l.X, l.Y = x, y
|
||||||
|
if l.GreaterEqual(start) && l.LessThan(end) {
|
||||||
|
c, _, _ := t.State.Cell(x, y)
|
||||||
|
ret += string(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start begins a new command in this terminal with a given view
|
||||||
|
func (t *Terminal) Start(execCmd []string, getOutput bool) error {
|
||||||
|
if len(execCmd) <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command(execCmd[0], execCmd[1:]...)
|
||||||
|
t.output = nil
|
||||||
|
if getOutput {
|
||||||
|
t.output = bytes.NewBuffer([]byte{})
|
||||||
|
}
|
||||||
|
Term, _, err := terminal.Start(&t.State, cmd, t.output)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t.Term = Term
|
||||||
|
t.getOutput = getOutput
|
||||||
|
t.Status = TTRunning
|
||||||
|
t.title = execCmd[0] + ":" + strconv.Itoa(cmd.Process.Pid)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
err := Term.Parse()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, "[Press enter to close]")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
screen.Redraw()
|
||||||
|
}
|
||||||
|
// TODO: close Term
|
||||||
|
// closeterm <- view.Num
|
||||||
|
}()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop stops execution of the terminal and sets the Status
|
||||||
|
// to TTDone
|
||||||
|
func (t *Terminal) Stop() {
|
||||||
|
t.Term.File().Close()
|
||||||
|
t.Term.Close()
|
||||||
|
if t.wait {
|
||||||
|
t.Status = TTDone
|
||||||
|
} else {
|
||||||
|
t.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close sets the Status to TTIdle indicating that the terminal
|
||||||
|
// is ready for a new command to execute
|
||||||
|
func (t *Terminal) Close() {
|
||||||
|
t.Status = TTIdle
|
||||||
|
// call the lua function that the user has given as a callback
|
||||||
|
if t.getOutput {
|
||||||
|
// TODO: plugin callback on Term emulator
|
||||||
|
// _, err := Call(t.callback, t.output.String())
|
||||||
|
// if err != nil && !strings.HasPrefix(err.Error(), "function does not exist") {
|
||||||
|
// TermMessage(err)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteString writes a given string to this terminal's pty
|
||||||
|
func (t *Terminal) WriteString(str string) {
|
||||||
|
t.Term.File().WriteString(str)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user