mirror of
https://github.com/diamondburned/cchat-gtk.git
synced 2024-11-01 03:54:16 +00:00
150 lines
3.2 KiB
Go
150 lines
3.2 KiB
Go
package commander
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/diamondburned/cchat"
|
|
"github.com/diamondburned/cchat-gtk/internal/gts"
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/primitives"
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/primitives/autoscroll"
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/primitives/completion"
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/primitives/scrollinput"
|
|
"github.com/diamondburned/cchat/utils/split"
|
|
"github.com/gotk3/gotk3/gdk"
|
|
"github.com/gotk3/gotk3/gtk"
|
|
)
|
|
|
|
var monospace = primitives.PrepareCSS(`
|
|
* {
|
|
font-family: monospace;
|
|
border-radius: 0;
|
|
}
|
|
`)
|
|
|
|
type Session struct {
|
|
*gtk.Box
|
|
|
|
cmder cchat.Commander
|
|
cmplt *completion.Completer
|
|
buffer *Buffer
|
|
|
|
inputbuf *gtk.TextBuffer
|
|
|
|
// words []string
|
|
// index int
|
|
}
|
|
|
|
func SpawnDialog(buf *Buffer) {
|
|
s := NewSession(buf)
|
|
s.Show()
|
|
|
|
h, _ := gtk.HeaderBarNew()
|
|
h.SetTitle("Commander: " + buf.name)
|
|
h.SetShowCloseButton(true)
|
|
h.Show()
|
|
|
|
d, _ := gts.NewEmptyModalDialog()
|
|
d.SetDefaultSize(450, 250)
|
|
d.SetTitlebar(h)
|
|
d.Add(s)
|
|
d.Show()
|
|
}
|
|
|
|
func NewSession(buf *Buffer) *Session {
|
|
view, _ := gtk.TextViewNewWithBuffer(buf.TextBuffer)
|
|
view.SetEditable(false)
|
|
view.SetProperty("monospace", true)
|
|
view.SetPixelsAboveLines(1)
|
|
view.SetWrapMode(gtk.WRAP_WORD_CHAR)
|
|
view.SetBorderWidth(8)
|
|
view.Show()
|
|
|
|
scroll := autoscroll.NewScrolledWindow()
|
|
scroll.SetPolicy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
|
|
scroll.Add(view)
|
|
scroll.Show()
|
|
|
|
input, _ := gtk.TextViewNew()
|
|
input.SetSizeRequest(-1, 35) // magic height 35px
|
|
input.SetBorderWidth(8)
|
|
primitives.AttachCSS(input, monospace)
|
|
input.Show()
|
|
|
|
inputbuf, _ := input.GetBuffer()
|
|
|
|
inputscroll := scrollinput.NewH(input)
|
|
inputscroll.Show()
|
|
|
|
sep, _ := gtk.SeparatorNew(gtk.ORIENTATION_HORIZONTAL)
|
|
sep.Show()
|
|
|
|
b, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
|
|
b.PackStart(scroll, true, true, 0)
|
|
b.PackStart(sep, false, false, 0)
|
|
b.PackStart(inputscroll, false, false, 0)
|
|
|
|
completer := completion.NewCompleter(input)
|
|
completer.Splitter = split.ArgsIndexed
|
|
completer.SetCompleter(buf.cmder.AsCompleter())
|
|
|
|
session := &Session{
|
|
Box: b,
|
|
cmder: buf.cmder,
|
|
cmplt: completer,
|
|
buffer: buf,
|
|
inputbuf: inputbuf,
|
|
}
|
|
|
|
input.Connect("key-press-event", session.inputActivate)
|
|
input.GrabFocus()
|
|
|
|
primitives.AddClass(b, "commander")
|
|
primitives.AddClass(view, "command-buffer")
|
|
primitives.AddClass(input, "command-input")
|
|
|
|
return session
|
|
}
|
|
|
|
func (s *Session) inputActivate(v *gtk.TextView, ev *gdk.Event) bool {
|
|
// If the keypress is not enter, then ignore.
|
|
if kev := gdk.EventKeyNewFromEvent(ev); kev.KeyVal() != gdk.KEY_Return {
|
|
return false
|
|
}
|
|
|
|
// Get the slice of words.
|
|
var words = s.cmplt.Content()
|
|
// If the input is empty, then ignore.
|
|
if len(words) == 0 {
|
|
return true
|
|
}
|
|
|
|
// Clear the entry.
|
|
s.inputbuf.Delete(s.inputbuf.GetBounds())
|
|
|
|
var then = time.Now()
|
|
s.buffer.Systemlnf("%s > %q", then.Format(time.Kitchen), words)
|
|
|
|
go func() {
|
|
out, err := s.cmder.Run(words)
|
|
|
|
gts.ExecAsync(func() {
|
|
if out != nil {
|
|
s.buffer.WriteOutput(out)
|
|
}
|
|
|
|
if err != nil {
|
|
s.buffer.WriteError(err)
|
|
}
|
|
|
|
var now = time.Now()
|
|
s.buffer.Systemlnf(
|
|
"%s: Finished running command, took %s.",
|
|
now.Format(time.Kitchen),
|
|
now.Sub(then).String(),
|
|
)
|
|
})
|
|
}()
|
|
|
|
return true
|
|
}
|