mirror of
https://github.com/zyedidia/micro.git
synced 2026-03-16 05:47:06 +09:00
Almost done terminal emulator
This commit is contained in:
@@ -818,7 +818,7 @@ func (h *BufHandler) SelectAll() bool {
|
|||||||
func (h *BufHandler) OpenFile() bool {
|
func (h *BufHandler) OpenFile() bool {
|
||||||
InfoBar.Prompt("> ", "open ", "Open", nil, func(resp string, canceled bool) {
|
InfoBar.Prompt("> ", "open ", "Open", nil, func(resp string, canceled bool) {
|
||||||
if !canceled {
|
if !canceled {
|
||||||
HandleCommand(resp)
|
h.HandleCommand(resp)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return false
|
return false
|
||||||
@@ -989,7 +989,7 @@ func (h *BufHandler) ShellMode() bool {
|
|||||||
func (h *BufHandler) CommandMode() bool {
|
func (h *BufHandler) CommandMode() bool {
|
||||||
InfoBar.Prompt("> ", "", "Command", nil, func(resp string, canceled bool) {
|
InfoBar.Prompt("> ", "", "Command", nil, func(resp string, canceled bool) {
|
||||||
if !canceled {
|
if !canceled {
|
||||||
HandleCommand(resp)
|
h.HandleCommand(resp)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return false
|
return false
|
||||||
@@ -1023,6 +1023,9 @@ func (h *BufHandler) Quit() bool {
|
|||||||
InfoBar.YNPrompt("Save changes to "+h.Buf.GetName()+" before closing? (y,n,esc)", func(yes, canceled bool) {
|
InfoBar.YNPrompt("Save changes to "+h.Buf.GetName()+" before closing? (y,n,esc)", func(yes, canceled bool) {
|
||||||
if !canceled && !yes {
|
if !canceled && !yes {
|
||||||
quit()
|
quit()
|
||||||
|
} else if !canceled && yes {
|
||||||
|
h.Save()
|
||||||
|
quit()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@@ -1040,7 +1043,7 @@ func (h *BufHandler) QuitAll() bool {
|
|||||||
func (h *BufHandler) AddTab() bool {
|
func (h *BufHandler) AddTab() bool {
|
||||||
width, height := screen.Screen.Size()
|
width, height := screen.Screen.Size()
|
||||||
b := buffer.NewBufferFromString("", "", buffer.BTDefault)
|
b := buffer.NewBufferFromString("", "", buffer.BTDefault)
|
||||||
tp := NewTabPane(0, 0, width, height-1, b)
|
tp := NewTabFromBuffer(0, 0, width, height-1, b)
|
||||||
Tabs.AddTab(tp)
|
Tabs.AddTab(tp)
|
||||||
Tabs.SetActive(len(Tabs.List) - 1)
|
Tabs.SetActive(len(Tabs.List) - 1)
|
||||||
|
|
||||||
|
|||||||
@@ -111,6 +111,14 @@ func NewBufHandler(buf *buffer.Buffer, win display.Window) *BufHandler {
|
|||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *BufHandler) ID() uint64 {
|
||||||
|
return h.splitID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *BufHandler) Name() string {
|
||||||
|
return h.Buf.GetName()
|
||||||
|
}
|
||||||
|
|
||||||
// HandleEvent executes the tcell event properly
|
// HandleEvent executes the tcell event properly
|
||||||
// TODO: multiple actions bound to one key
|
// TODO: multiple actions bound to one key
|
||||||
func (h *BufHandler) HandleEvent(event tcell.Event) {
|
func (h *BufHandler) HandleEvent(event tcell.Event) {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
|
|
||||||
// A Command contains an action (a function to call) as well as information about how to autocomplete the command
|
// A Command contains an action (a function to call) as well as information about how to autocomplete the command
|
||||||
type Command struct {
|
type Command struct {
|
||||||
action func([]string)
|
action func(*BufHandler, []string)
|
||||||
completions []Completion
|
completions []Completion
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,37 +24,33 @@ type StrCommand struct {
|
|||||||
|
|
||||||
var commands map[string]Command
|
var commands map[string]Command
|
||||||
|
|
||||||
var commandActions map[string]func([]string)
|
var commandActions = map[string]func(*BufHandler, []string){
|
||||||
|
"Set": (*BufHandler).SetCmd,
|
||||||
func init() {
|
"SetLocal": (*BufHandler).SetLocalCmd,
|
||||||
commandActions = map[string]func([]string){
|
"Show": (*BufHandler).ShowCmd,
|
||||||
"Set": Set,
|
"ShowKey": (*BufHandler).ShowKeyCmd,
|
||||||
"SetLocal": SetLocal,
|
"Run": (*BufHandler).RunCmd,
|
||||||
"Show": Show,
|
"Bind": (*BufHandler).BindCmd,
|
||||||
"ShowKey": ShowKey,
|
"Quit": (*BufHandler).QuitCmd,
|
||||||
"Run": Run,
|
"Save": (*BufHandler).SaveCmd,
|
||||||
"Bind": Bind,
|
"Replace": (*BufHandler).ReplaceCmd,
|
||||||
"Quit": Quit,
|
"ReplaceAll": (*BufHandler).ReplaceAllCmd,
|
||||||
"Save": Save,
|
"VSplit": (*BufHandler).VSplitCmd,
|
||||||
"Replace": Replace,
|
"HSplit": (*BufHandler).HSplitCmd,
|
||||||
"ReplaceAll": ReplaceAll,
|
"Tab": (*BufHandler).NewTabCmd,
|
||||||
"VSplit": VSplit,
|
"Help": (*BufHandler).HelpCmd,
|
||||||
"HSplit": HSplit,
|
"Eval": (*BufHandler).EvalCmd,
|
||||||
"Tab": NewTab,
|
"ToggleLog": (*BufHandler).ToggleLogCmd,
|
||||||
"Help": Help,
|
"Plugin": (*BufHandler).PluginCmd,
|
||||||
"Eval": Eval,
|
"Reload": (*BufHandler).ReloadCmd,
|
||||||
"ToggleLog": ToggleLog,
|
"Cd": (*BufHandler).CdCmd,
|
||||||
"Plugin": PluginCmd,
|
"Pwd": (*BufHandler).PwdCmd,
|
||||||
"Reload": Reload,
|
"Open": (*BufHandler).OpenCmd,
|
||||||
"Cd": Cd,
|
"TabSwitch": (*BufHandler).TabSwitchCmd,
|
||||||
"Pwd": Pwd,
|
"Term": (*BufHandler).TermCmd,
|
||||||
"Open": Open,
|
"MemUsage": (*BufHandler).MemUsageCmd,
|
||||||
"TabSwitch": TabSwitch,
|
"Retab": (*BufHandler).RetabCmd,
|
||||||
"Term": Term,
|
"Raw": (*BufHandler).RawCmd,
|
||||||
"MemUsage": MemUsage,
|
|
||||||
"Retab": Retab,
|
|
||||||
"Raw": Raw,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitCommands initializes the default commands
|
// InitCommands initializes the default commands
|
||||||
@@ -123,7 +119,7 @@ func CommandEditAction(prompt string) BufKeyAction {
|
|||||||
return func(h *BufHandler) bool {
|
return func(h *BufHandler) bool {
|
||||||
InfoBar.Prompt("> ", prompt, "Command", nil, func(resp string, canceled bool) {
|
InfoBar.Prompt("> ", prompt, "Command", nil, func(resp string, canceled bool) {
|
||||||
if !canceled {
|
if !canceled {
|
||||||
HandleCommand(resp)
|
MainTab().CurPane().HandleCommand(resp)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return false
|
return false
|
||||||
@@ -134,46 +130,46 @@ func CommandEditAction(prompt string) BufKeyAction {
|
|||||||
// given command
|
// given command
|
||||||
func CommandAction(cmd string) BufKeyAction {
|
func CommandAction(cmd string) BufKeyAction {
|
||||||
return func(h *BufHandler) bool {
|
return func(h *BufHandler) bool {
|
||||||
HandleCommand(cmd)
|
MainTab().CurPane().HandleCommand(cmd)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PluginCmd installs, removes, updates, lists, or searches for given plugins
|
// PluginCmd installs, removes, updates, lists, or searches for given plugins
|
||||||
func PluginCmd(args []string) {
|
func (h *BufHandler) PluginCmd(args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retab changes all spaces to tabs or all tabs to spaces
|
// RetabCmd changes all spaces to tabs or all tabs to spaces
|
||||||
// depending on the user's settings
|
// depending on the user's settings
|
||||||
func Retab(args []string) {
|
func (h *BufHandler) RetabCmd(args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raw opens a new raw view which displays the escape sequences micro
|
// RawCmd opens a new raw view which displays the escape sequences micro
|
||||||
// is receiving in real-time
|
// is receiving in real-time
|
||||||
func Raw(args []string) {
|
func (h *BufHandler) RawCmd(args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TabSwitch switches to a given tab either by name or by number
|
// TabSwitchCmd switches to a given tab either by name or by number
|
||||||
func TabSwitch(args []string) {
|
func (h *BufHandler) TabSwitchCmd(args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cd changes the current working directory
|
// CdCmd changes the current working directory
|
||||||
func Cd(args []string) {
|
func (h *BufHandler) CdCmd(args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MemUsage prints micro's memory usage
|
// MemUsageCmd prints micro's memory usage
|
||||||
// Alloc shows how many bytes are currently in use
|
// Alloc shows how many bytes are currently in use
|
||||||
// Sys shows how many bytes have been requested from the operating system
|
// Sys shows how many bytes have been requested from the operating system
|
||||||
// NumGC shows how many times the GC has been run
|
// NumGC shows how many times the GC has been run
|
||||||
// Note that Go commonly reserves more memory from the OS than is currently in-use/required
|
// Note that Go commonly reserves more memory from the OS than is currently in-use/required
|
||||||
// Additionally, even if Go returns memory to the OS, the OS does not always claim it because
|
// Additionally, even if Go returns memory to the OS, the OS does not always claim it because
|
||||||
// there may be plenty of memory to spare
|
// there may be plenty of memory to spare
|
||||||
func MemUsage(args []string) {
|
func (h *BufHandler) MemUsageCmd(args []string) {
|
||||||
InfoBar.Message(util.GetMemStats())
|
InfoBar.Message(util.GetMemStats())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pwd prints the current working directory
|
// PwdCmd prints the current working directory
|
||||||
func Pwd(args []string) {
|
func (h *BufHandler) PwdCmd(args []string) {
|
||||||
wd, err := os.Getwd()
|
wd, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InfoBar.Message(err.Error())
|
InfoBar.Message(err.Error())
|
||||||
@@ -182,68 +178,86 @@ func Pwd(args []string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open opens a new buffer with a given filename
|
// OpenCmd opens a new buffer with a given filename
|
||||||
func Open(args []string) {
|
func (h *BufHandler) OpenCmd(args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToggleLog toggles the log view
|
// ToggleLogCmd toggles the log view
|
||||||
func ToggleLog(args []string) {
|
func (h *BufHandler) ToggleLogCmd(args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reload reloads all files (syntax files, colorschemes...)
|
// ReloadCmd reloads all files (syntax files, colorschemes...)
|
||||||
func Reload(args []string) {
|
func (h *BufHandler) ReloadCmd(args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Help tries to open the given help page in a horizontal split
|
// HelpCmd tries to open the given help page in a horizontal split
|
||||||
func Help(args []string) {
|
func (h *BufHandler) HelpCmd(args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// VSplit opens a vertical split with file given in the first argument
|
// VSplitCmd opens a vertical split with file given in the first argument
|
||||||
// If no file is given, it opens an empty buffer in a new split
|
// If no file is given, it opens an empty buffer in a new split
|
||||||
func VSplit(args []string) {
|
func (h *BufHandler) VSplitCmd(args []string) {
|
||||||
buf, err := buffer.NewBufferFromFile(args[0], buffer.BTDefault)
|
buf, err := buffer.NewBufferFromFile(args[0], buffer.BTDefault)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InfoBar.Error(err)
|
InfoBar.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
MainTab().CurPane().vsplit(buf)
|
h.vsplit(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HSplit opens a horizontal split with file given in the first argument
|
// HSplitCmd opens a horizontal split with file given in the first argument
|
||||||
// If no file is given, it opens an empty buffer in a new split
|
// If no file is given, it opens an empty buffer in a new split
|
||||||
func HSplit(args []string) {
|
func (h *BufHandler) HSplitCmd(args []string) {
|
||||||
buf, err := buffer.NewBufferFromFile(args[0], buffer.BTDefault)
|
buf, err := buffer.NewBufferFromFile(args[0], buffer.BTDefault)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InfoBar.Error(err)
|
InfoBar.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
MainTab().CurPane().hsplit(buf)
|
h.hsplit(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Eval evaluates a lua expression
|
// EvalCmd evaluates a lua expression
|
||||||
func Eval(args []string) {
|
func (h *BufHandler) EvalCmd(args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTab opens the given file in a new tab
|
// NewTabCmd opens the given file in a new tab
|
||||||
func NewTab(args []string) {
|
func (h *BufHandler) NewTabCmd(args []string) {
|
||||||
|
width, height := screen.Screen.Size()
|
||||||
|
if len(args) > 0 {
|
||||||
|
for _, a := range args {
|
||||||
|
b, err := buffer.NewBufferFromFile(a, buffer.BTDefault)
|
||||||
|
if err != nil {
|
||||||
|
InfoBar.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tp := NewTabFromBuffer(0, 0, width, height-1, b)
|
||||||
|
Tabs.AddTab(tp)
|
||||||
|
Tabs.SetActive(len(Tabs.List) - 1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
b := buffer.NewBufferFromString("", "", buffer.BTDefault)
|
||||||
|
tp := NewTabFromBuffer(0, 0, width, height-1, b)
|
||||||
|
Tabs.AddTab(tp)
|
||||||
|
Tabs.SetActive(len(Tabs.List) - 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set sets an option
|
// SetCmd sets an option
|
||||||
func Set(args []string) {
|
func (h *BufHandler) SetCmd(args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetLocal sets an option local to the buffer
|
// SetLocalCmd sets an option local to the buffer
|
||||||
func SetLocal(args []string) {
|
func (h *BufHandler) SetLocalCmd(args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show shows the value of the given option
|
// ShowCmd shows the value of the given option
|
||||||
func Show(args []string) {
|
func (h *BufHandler) ShowCmd(args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShowKey displays the action that a key is bound to
|
// ShowKeyCmd displays the action that a key is bound to
|
||||||
func ShowKey(args []string) {
|
func (h *BufHandler) ShowKeyCmd(args []string) {
|
||||||
if len(args) < 1 {
|
if len(args) < 1 {
|
||||||
InfoBar.Error("Please provide a key to show")
|
InfoBar.Error("Please provide a key to show")
|
||||||
return
|
return
|
||||||
@@ -256,12 +270,12 @@ func ShowKey(args []string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind creates a new keybinding
|
// BindCmd creates a new keybinding
|
||||||
func Bind(args []string) {
|
func (h *BufHandler) BindCmd(args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run runs a shell command in the background
|
// RunCmd runs a shell command in the background
|
||||||
func Run(args []string) {
|
func (h *BufHandler) RunCmd(args []string) {
|
||||||
runf, err := shell.RunBackgroundShell(shellwords.Join(args...))
|
runf, err := shell.RunBackgroundShell(shellwords.Join(args...))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InfoBar.Error(err)
|
InfoBar.Error(err)
|
||||||
@@ -273,28 +287,54 @@ func Run(args []string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quit closes the main view
|
// QuitCmd closes the main view
|
||||||
func Quit(args []string) {
|
func (h *BufHandler) QuitCmd(args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save saves the buffer in the main view
|
// SaveCmd saves the buffer in the main view
|
||||||
func Save(args []string) {
|
func (h *BufHandler) SaveCmd(args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace runs search and replace
|
// ReplaceCmd runs search and replace
|
||||||
func Replace(args []string) {
|
func (h *BufHandler) ReplaceCmd(args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReplaceAll replaces search term all at once
|
// ReplaceAllCmd replaces search term all at once
|
||||||
func ReplaceAll(args []string) {
|
func (h *BufHandler) ReplaceAllCmd(args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Term opens a terminal in the current view
|
// TermCmd opens a terminal in the current view
|
||||||
func Term(args []string) {
|
func (h *BufHandler) TermCmd(args []string) {
|
||||||
|
ps := MainTab().Panes
|
||||||
|
|
||||||
|
term := func(i int) {
|
||||||
|
v := h.GetView()
|
||||||
|
t := new(shell.Terminal)
|
||||||
|
t.Start(args, false, true)
|
||||||
|
MainTab().Panes[i] = NewTermHandler(v.X, v.Y, v.Width, v.Height, t, h.ID())
|
||||||
|
MainTab().SetActive(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, p := range ps {
|
||||||
|
if p.ID() == h.ID() {
|
||||||
|
if h.Buf.Modified() {
|
||||||
|
InfoBar.YNPrompt("Save changes to "+h.Buf.GetName()+" before closing? (y,n,esc)", func(yes, canceled bool) {
|
||||||
|
if !canceled && !yes {
|
||||||
|
term(i)
|
||||||
|
} else if !canceled && yes {
|
||||||
|
h.Save()
|
||||||
|
term(i)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
term(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleCommand handles input from the user
|
// HandleCommand handles input from the user
|
||||||
func HandleCommand(input string) {
|
func (h *BufHandler) HandleCommand(input string) {
|
||||||
args, err := shellwords.Split(input)
|
args, err := shellwords.Split(input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InfoBar.Error("Error parsing args ", err)
|
InfoBar.Error("Error parsing args ", err)
|
||||||
@@ -306,6 +346,6 @@ func HandleCommand(input string) {
|
|||||||
if _, ok := commands[inputCmd]; !ok {
|
if _, ok := commands[inputCmd]; !ok {
|
||||||
InfoBar.Error("Unknown command ", inputCmd)
|
InfoBar.Error("Unknown command ", inputCmd)
|
||||||
} else {
|
} else {
|
||||||
commands[inputCmd].action(args[1:])
|
commands[inputCmd].action(h, args[1:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ import (
|
|||||||
"github.com/zyedidia/micro/cmd/micro/buffer"
|
"github.com/zyedidia/micro/cmd/micro/buffer"
|
||||||
"github.com/zyedidia/micro/cmd/micro/display"
|
"github.com/zyedidia/micro/cmd/micro/display"
|
||||||
"github.com/zyedidia/micro/cmd/micro/info"
|
"github.com/zyedidia/micro/cmd/micro/info"
|
||||||
"github.com/zyedidia/micro/cmd/micro/views"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Pane interface {
|
type Pane interface {
|
||||||
Handler
|
Handler
|
||||||
display.Window
|
display.Window
|
||||||
ID() uint64
|
ID() uint64
|
||||||
|
Name() string
|
||||||
}
|
}
|
||||||
|
|
||||||
type EditPane struct {
|
type EditPane struct {
|
||||||
@@ -34,18 +34,6 @@ func NewBufEditPane(x, y, width, height int, b *buffer.Buffer) *EditPane {
|
|||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTabPane(x, y, width, height int, b *buffer.Buffer) *TabPane {
|
|
||||||
t := new(TabPane)
|
|
||||||
t.Node = views.NewRoot(x, y, width, height)
|
|
||||||
t.UIWindow = display.NewUIWindow(t.Node)
|
|
||||||
|
|
||||||
e := NewBufEditPane(x, y, width, height, b)
|
|
||||||
e.splitID = t.ID()
|
|
||||||
|
|
||||||
t.Panes = append(t.Panes, e)
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewInfoBar() *InfoPane {
|
func NewInfoBar() *InfoPane {
|
||||||
e := new(InfoPane)
|
e := new(InfoPane)
|
||||||
ib := info.NewBuffer()
|
ib := info.NewBuffer()
|
||||||
|
|||||||
@@ -38,4 +38,5 @@ type MouseAction func(Handler, tcell.EventMouse) bool
|
|||||||
// appropriately
|
// appropriately
|
||||||
type Handler interface {
|
type Handler interface {
|
||||||
HandleEvent(tcell.Event)
|
HandleEvent(tcell.Event)
|
||||||
|
HandleCommand(string)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,19 +10,19 @@ import (
|
|||||||
|
|
||||||
type TabList struct {
|
type TabList struct {
|
||||||
*display.TabWindow
|
*display.TabWindow
|
||||||
List []*TabPane
|
List []*Tab
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTabList(bufs []*buffer.Buffer) *TabList {
|
func NewTabList(bufs []*buffer.Buffer) *TabList {
|
||||||
w, h := screen.Screen.Size()
|
w, h := screen.Screen.Size()
|
||||||
tl := new(TabList)
|
tl := new(TabList)
|
||||||
tl.List = make([]*TabPane, len(bufs))
|
tl.List = make([]*Tab, len(bufs))
|
||||||
if len(bufs) > 1 {
|
if len(bufs) > 1 {
|
||||||
for i, b := range bufs {
|
for i, b := range bufs {
|
||||||
tl.List[i] = NewTabPane(0, 1, w, h-2, b)
|
tl.List[i] = NewTabFromBuffer(0, 1, w, h-2, b)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tl.List[0] = NewTabPane(0, 0, w, h-1, bufs[0])
|
tl.List[0] = NewTabFromBuffer(0, 0, w, h-1, bufs[0])
|
||||||
}
|
}
|
||||||
tl.TabWindow = display.NewTabWindow(w, 0)
|
tl.TabWindow = display.NewTabWindow(w, 0)
|
||||||
tl.Names = make([]string, len(bufs))
|
tl.Names = make([]string, len(bufs))
|
||||||
@@ -33,11 +33,11 @@ func NewTabList(bufs []*buffer.Buffer) *TabList {
|
|||||||
func (t *TabList) UpdateNames() {
|
func (t *TabList) UpdateNames() {
|
||||||
t.Names = t.Names[:0]
|
t.Names = t.Names[:0]
|
||||||
for _, p := range t.List {
|
for _, p := range t.List {
|
||||||
t.Names = append(t.Names, p.Panes[p.active].Buf.GetName())
|
t.Names = append(t.Names, p.Panes[p.active].Name())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TabList) AddTab(p *TabPane) {
|
func (t *TabList) AddTab(p *Tab) {
|
||||||
t.List = append(t.List, p)
|
t.List = append(t.List, p)
|
||||||
t.Resize()
|
t.Resize()
|
||||||
t.UpdateNames()
|
t.UpdateNames()
|
||||||
@@ -48,7 +48,7 @@ func (t *TabList) RemoveTab(id uint64) {
|
|||||||
if len(p.Panes) == 0 {
|
if len(p.Panes) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if p.Panes[0].splitID == id {
|
if p.Panes[0].ID() == id {
|
||||||
copy(t.List[i:], t.List[i+1:])
|
copy(t.List[i:], t.List[i+1:])
|
||||||
t.List[len(t.List)-1] = nil
|
t.List[len(t.List)-1] = nil
|
||||||
t.List = t.List[:len(t.List)-1]
|
t.List = t.List[:len(t.List)-1]
|
||||||
@@ -118,29 +118,41 @@ func InitTabs(bufs []*buffer.Buffer) {
|
|||||||
Tabs = NewTabList(bufs)
|
Tabs = NewTabList(bufs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MainTab() *TabPane {
|
func MainTab() *Tab {
|
||||||
return Tabs.List[Tabs.Active()]
|
return Tabs.List[Tabs.Active()]
|
||||||
}
|
}
|
||||||
|
|
||||||
// A TabPane represents a single tab
|
// A Tab represents a single tab
|
||||||
// It consists of a list of edit panes (the open buffers),
|
// It consists of a list of edit panes (the open buffers),
|
||||||
// a split tree (stored as just the root node), and a uiwindow
|
// a split tree (stored as just the root node), and a uiwindow
|
||||||
// to display the UI elements like the borders between splits
|
// to display the UI elements like the borders between splits
|
||||||
type TabPane struct {
|
type Tab struct {
|
||||||
*views.Node
|
*views.Node
|
||||||
*display.UIWindow
|
*display.UIWindow
|
||||||
Panes []*EditPane
|
Panes []Pane
|
||||||
active int
|
active int
|
||||||
|
|
||||||
resizing *views.Node // node currently being resized
|
resizing *views.Node // node currently being resized
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewTabFromBuffer(x, y, width, height int, b *buffer.Buffer) *Tab {
|
||||||
|
t := new(Tab)
|
||||||
|
t.Node = views.NewRoot(x, y, width, height)
|
||||||
|
t.UIWindow = display.NewUIWindow(t.Node)
|
||||||
|
|
||||||
|
e := NewBufEditPane(x, y, width, height, b)
|
||||||
|
e.splitID = t.ID()
|
||||||
|
|
||||||
|
t.Panes = append(t.Panes, e)
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
// HandleEvent takes a tcell event and usually dispatches it to the current
|
// HandleEvent takes a tcell event and usually dispatches it to the current
|
||||||
// active pane. However if the event is a resize or a mouse event where the user
|
// active pane. However if the event is a resize or a mouse event where the user
|
||||||
// is interacting with the UI (resizing splits) then the event is consumed here
|
// is interacting with the UI (resizing splits) then the event is consumed here
|
||||||
// If the event is a mouse event in a pane, that pane will become active and get
|
// If the event is a mouse event in a pane, that pane will become active and get
|
||||||
// the event
|
// the event
|
||||||
func (t *TabPane) HandleEvent(event tcell.Event) {
|
func (t *Tab) HandleEvent(event tcell.Event) {
|
||||||
switch e := event.(type) {
|
switch e := event.(type) {
|
||||||
case *tcell.EventMouse:
|
case *tcell.EventMouse:
|
||||||
mx, my := e.Position()
|
mx, my := e.Position()
|
||||||
@@ -192,7 +204,7 @@ func (t *TabPane) HandleEvent(event tcell.Event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetActive changes the currently active pane to the specified index
|
// SetActive changes the currently active pane to the specified index
|
||||||
func (t *TabPane) SetActive(i int) {
|
func (t *Tab) SetActive(i int) {
|
||||||
t.active = i
|
t.active = i
|
||||||
for j, p := range t.Panes {
|
for j, p := range t.Panes {
|
||||||
if j == i {
|
if j == i {
|
||||||
@@ -204,9 +216,9 @@ func (t *TabPane) SetActive(i int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetPane returns the pane with the given split index
|
// GetPane returns the pane with the given split index
|
||||||
func (t *TabPane) GetPane(splitid uint64) int {
|
func (t *Tab) GetPane(splitid uint64) int {
|
||||||
for i, p := range t.Panes {
|
for i, p := range t.Panes {
|
||||||
if p.splitID == splitid {
|
if p.ID() == splitid {
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -214,16 +226,16 @@ func (t *TabPane) GetPane(splitid uint64) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove pane removes the pane with the given index
|
// Remove pane removes the pane with the given index
|
||||||
func (t *TabPane) RemovePane(i int) {
|
func (t *Tab) RemovePane(i int) {
|
||||||
copy(t.Panes[i:], t.Panes[i+1:])
|
copy(t.Panes[i:], t.Panes[i+1:])
|
||||||
t.Panes[len(t.Panes)-1] = nil
|
t.Panes[len(t.Panes)-1] = nil
|
||||||
t.Panes = t.Panes[:len(t.Panes)-1]
|
t.Panes = t.Panes[:len(t.Panes)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resize resizes all panes according to their corresponding split nodes
|
// Resize resizes all panes according to their corresponding split nodes
|
||||||
func (t *TabPane) Resize() {
|
func (t *Tab) Resize() {
|
||||||
for _, p := range t.Panes {
|
for _, p := range t.Panes {
|
||||||
n := t.GetNode(p.splitID)
|
n := t.GetNode(p.ID())
|
||||||
pv := p.GetView()
|
pv := p.GetView()
|
||||||
offset := 0
|
offset := 0
|
||||||
if n.X != 0 {
|
if n.X != 0 {
|
||||||
@@ -236,6 +248,6 @@ func (t *TabPane) Resize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CurPane returns the currently active pane
|
// CurPane returns the currently active pane
|
||||||
func (t *TabPane) CurPane() *EditPane {
|
func (t *Tab) CurPane() Pane {
|
||||||
return t.Panes[t.active]
|
return t.Panes[t.active]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
package action
|
package action
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/zyedidia/clipboard"
|
"github.com/zyedidia/clipboard"
|
||||||
"github.com/zyedidia/micro/cmd/micro/display"
|
"github.com/zyedidia/micro/cmd/micro/display"
|
||||||
|
"github.com/zyedidia/micro/cmd/micro/screen"
|
||||||
"github.com/zyedidia/micro/cmd/micro/shell"
|
"github.com/zyedidia/micro/cmd/micro/shell"
|
||||||
"github.com/zyedidia/tcell"
|
"github.com/zyedidia/tcell"
|
||||||
"github.com/zyedidia/terminal"
|
"github.com/zyedidia/terminal"
|
||||||
@@ -13,6 +16,40 @@ type TermHandler struct {
|
|||||||
display.Window
|
display.Window
|
||||||
|
|
||||||
mouseReleased bool
|
mouseReleased bool
|
||||||
|
id uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTermHandler(x, y, w, h int, t *shell.Terminal, id uint64) *TermHandler {
|
||||||
|
th := new(TermHandler)
|
||||||
|
th.Terminal = t
|
||||||
|
th.id = id
|
||||||
|
th.Window = display.NewTermWindow(x, y, w, h, t)
|
||||||
|
return th
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TermHandler) ID() uint64 {
|
||||||
|
return t.id
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TermHandler) Quit() {
|
||||||
|
if len(MainTab().Panes) > 1 {
|
||||||
|
t.Unsplit()
|
||||||
|
} else if len(Tabs.List) > 1 {
|
||||||
|
Tabs.RemoveTab(t.id)
|
||||||
|
} else {
|
||||||
|
screen.Screen.Fini()
|
||||||
|
InfoBar.Close()
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TermHandler) Unsplit() {
|
||||||
|
n := MainTab().GetNode(t.id)
|
||||||
|
n.Unsplit()
|
||||||
|
|
||||||
|
MainTab().RemovePane(MainTab().GetPane(t.id))
|
||||||
|
MainTab().Resize()
|
||||||
|
MainTab().SetActive(len(MainTab().Panes) - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleEvent handles a tcell event by forwarding it to the terminal emulator
|
// HandleEvent handles a tcell event by forwarding it to the terminal emulator
|
||||||
@@ -25,6 +62,7 @@ func (t *TermHandler) HandleEvent(event tcell.Event) {
|
|||||||
switch e.Key() {
|
switch e.Key() {
|
||||||
case tcell.KeyEscape, tcell.KeyCtrlQ, tcell.KeyEnter:
|
case tcell.KeyEscape, tcell.KeyCtrlQ, tcell.KeyEnter:
|
||||||
t.Close()
|
t.Close()
|
||||||
|
t.Quit()
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,3 +102,7 @@ func (t *TermHandler) HandleEvent(event tcell.Event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *TermHandler) HandleCommand(input string) {
|
||||||
|
InfoBar.Error("Commands are unsupported in term for now")
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,9 +18,11 @@ type TermWindow struct {
|
|||||||
|
|
||||||
func NewTermWindow(x, y, w, h int, term *shell.Terminal) *TermWindow {
|
func NewTermWindow(x, y, w, h int, term *shell.Terminal) *TermWindow {
|
||||||
tw := new(TermWindow)
|
tw := new(TermWindow)
|
||||||
|
tw.View = new(View)
|
||||||
tw.Terminal = term
|
tw.Terminal = term
|
||||||
tw.X, tw.Y = x, y
|
tw.X, tw.Y = x, y
|
||||||
tw.Width, tw.Height = w, h
|
tw.Width, tw.Height = w, h
|
||||||
|
tw.Resize(w, h)
|
||||||
return tw
|
return tw
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
type TermType int
|
type TermType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TTIdle = iota // Waiting for a new command
|
TTClose = iota // Should be closed
|
||||||
TTRunning // Currently running a command
|
TTRunning // Currently running a command
|
||||||
TTDone // Finished running a command
|
TTDone // Finished running a command
|
||||||
)
|
)
|
||||||
@@ -38,6 +38,10 @@ func (t *Terminal) HasSelection() bool {
|
|||||||
return t.Selection[0] != t.Selection[1]
|
return t.Selection[0] != t.Selection[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) Name() string {
|
||||||
|
return t.title
|
||||||
|
}
|
||||||
|
|
||||||
// GetSelection returns the selected text
|
// GetSelection returns the selected text
|
||||||
func (t *Terminal) GetSelection(width int) string {
|
func (t *Terminal) GetSelection(width int) string {
|
||||||
start := t.Selection[0]
|
start := t.Selection[0]
|
||||||
@@ -60,7 +64,7 @@ func (t *Terminal) GetSelection(width int) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start begins a new command in this terminal with a given view
|
// Start begins a new command in this terminal with a given view
|
||||||
func (t *Terminal) Start(execCmd []string, getOutput bool) error {
|
func (t *Terminal) Start(execCmd []string, getOutput bool, wait bool) error {
|
||||||
if len(execCmd) <= 0 {
|
if len(execCmd) <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -78,6 +82,7 @@ func (t *Terminal) Start(execCmd []string, getOutput bool) error {
|
|||||||
t.getOutput = getOutput
|
t.getOutput = getOutput
|
||||||
t.Status = TTRunning
|
t.Status = TTRunning
|
||||||
t.title = execCmd[0] + ":" + strconv.Itoa(cmd.Process.Pid)
|
t.title = execCmd[0] + ":" + strconv.Itoa(cmd.Process.Pid)
|
||||||
|
t.wait = wait
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
@@ -88,6 +93,7 @@ func (t *Terminal) Start(execCmd []string, getOutput bool) error {
|
|||||||
}
|
}
|
||||||
screen.Redraw()
|
screen.Redraw()
|
||||||
}
|
}
|
||||||
|
t.Stop()
|
||||||
// TODO: close Term
|
// TODO: close Term
|
||||||
// closeterm <- view.Num
|
// closeterm <- view.Num
|
||||||
}()
|
}()
|
||||||
@@ -107,10 +113,10 @@ func (t *Terminal) Stop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close sets the Status to TTIdle indicating that the terminal
|
// Close sets the Status to TTClose indicating that the terminal
|
||||||
// is ready for a new command to execute
|
// is done and should be closed
|
||||||
func (t *Terminal) Close() {
|
func (t *Terminal) Close() {
|
||||||
t.Status = TTIdle
|
t.Status = TTClose
|
||||||
// call the lua function that the user has given as a callback
|
// call the lua function that the user has given as a callback
|
||||||
if t.getOutput {
|
if t.getOutput {
|
||||||
// TODO: plugin callback on Term emulator
|
// TODO: plugin callback on Term emulator
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package views
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -440,7 +439,6 @@ func (n *Node) unsplit(i int, h bool) {
|
|||||||
copy(n.children[i:], n.children[i+1:])
|
copy(n.children[i:], n.children[i+1:])
|
||||||
n.children[len(n.children)-1] = nil
|
n.children[len(n.children)-1] = nil
|
||||||
n.children = n.children[:len(n.children)-1]
|
n.children = n.children[:len(n.children)-1]
|
||||||
log.Println(len(n.children))
|
|
||||||
|
|
||||||
nonrs, numr := n.getResizeInfo(h)
|
nonrs, numr := n.getResizeInfo(h)
|
||||||
if numr == 0 {
|
if numr == 0 {
|
||||||
@@ -475,7 +473,6 @@ func (n *Node) Unsplit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if n.parent.IsLeaf() {
|
if n.parent.IsLeaf() {
|
||||||
log.Println("destroy parent")
|
|
||||||
n.parent.Unsplit()
|
n.parent.Unsplit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user