TUI IDE multiplexer?!
golang
tui
ide
1package main
2
3import (
4 "fmt"
5
6 "github.com/gdamore/tcell/v2"
7 "github.com/godbus/dbus/v5"
8 "github.com/godbus/dbus/v5/introspect"
9 "github.com/rivo/tview"
10)
11
12type Shells struct {
13 conn *dbus.Conn // Assigned from app.
14 env *[]string // Assigned from app.
15 setFocusFunc func(tview.Primitive) // Calls app's SetFocus
16
17 shells []*Term
18 lastFocusedShell int
19
20 *Resizable
21}
22
23func (s *Shells) Setup() error {
24 // UI
25 s.Resizable = NewResizable("shells", false)
26
27 // D-Bus
28 if err := app.Conn.ExportMethodTable(map[string]any{
29 "SetFocus": func() *dbus.Error {
30 if shell := s.GetLastFocusedShell(); shell != nil {
31 s.setFocusFunc(shell)
32 }
33 return nil
34 },
35 "SendString": func(str string) *dbus.Error {
36 if shell := s.GetLastFocusedShell(); shell != nil {
37 return shell.SendString(str)
38 }
39 return nil
40 },
41 "SendBytes": func(b []byte) *dbus.Error {
42 if shell := s.GetLastFocusedShell(); shell != nil {
43 return shell.SendBytes(b)
44 }
45 return nil
46 },
47 }, dbus.ObjectPath("/panels/shell/active"), "net.kettek.Aight.Panel"); err != nil {
48 return err
49 }
50 if err := app.Conn.Export(introspect.Introspectable(termIntro), dbus.ObjectPath("/panels/shell/active"), "org.freedesktop.DBus.Introspectable"); err != nil {
51 return err
52 }
53
54 return nil
55}
56
57func (s *Shells) Draw(screen tcell.Screen) {
58 s.Resizable.Draw(screen)
59 // Uh.. titles, I guess
60 for index, item := range s.items {
61 title := s.shells[index].state.Title()
62 if title == "" {
63 continue
64 }
65 x, y, w, _ := item.item.GetRect()
66 x1 := x + w/2 - len(title)/2
67 screen.PutStr(x1, y-1, title) // -1 y to draw over the gripper
68 }
69}
70
71func (s *Shells) Cleanup() error {
72 // D-Bus
73 for _, shell := range s.shells {
74 shell.RemoveFromConn(s.conn)
75 }
76
77 s.conn.Export(nil, dbus.ObjectPath("/panels/shell/active"), "org.freedesktop.DBus.Introspectable")
78 s.conn.Export(nil, dbus.ObjectPath("/panels/shell/active"), "net.kettek.Aight.Status")
79
80 return nil
81}
82
83func (s *Shells) AddShell() error {
84 id := len(s.shells)
85 shell := NewTerm(fmt.Sprintf("shell/%d", id), cfg.Shell)
86 shell.SetFocusFunc(func() {
87 s.lastFocusedShell = id
88 })
89
90 // Add focus handler.
91 if err := s.conn.ExportMethodTable(map[string]any{
92 "SetFocus": func() *dbus.Error {
93 if shell := s.GetShellByIndex(id); shell != nil {
94 s.setFocusFunc(shell)
95 }
96 return nil
97 },
98 "SendString": func(s string) *dbus.Error {
99 if _, err := shell.vt.File().WriteString(s); err != nil {
100 return dbus.NewError("Send", []any{err.Error()})
101 }
102 return nil
103 },
104 "SendBytes": func(b []byte) *dbus.Error {
105 if _, err := shell.vt.File().Write(b); err != nil {
106 return dbus.NewError("Send", []any{err.Error()})
107 }
108 return nil
109 },
110 }, dbus.ObjectPath(fmt.Sprintf("/panels/shell/%d", id)), "net.kettek.Aight.Panel"); err != nil {
111 return err
112 }
113
114 // Start 'er up.
115 if err := shell.Start(*s.env); err != nil {
116 return err
117 }
118
119 s.shells = append(s.shells, shell)
120
121 // Add to UI.
122 s.AddItem(shell, 0, false)
123
124 return shell.AddToConn(s.conn)
125}
126
127func (s *Shells) GetShellByIndex(id int) *Term {
128 if id > len(s.shells) {
129 return nil
130 }
131 return s.shells[id]
132}
133
134func (s *Shells) GetLastFocusedShell() *Term {
135 return s.GetShellByIndex(s.lastFocusedShell)
136}