Go bindings for libghostty-vt.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

terminal: pass *Terminal as first parameter to effect callbacks

Previously, effect callback function types (WritePtyFn, BellFn,
TitleChangedFn, etc.) did not receive the terminal that triggered
them. This forced callers using the functional option pattern to
pre-declare a var and use a split assignment so closures could
capture it, as seen in the effects example.

All effect callback types now take *Terminal as their first
parameter. The C trampolines already recovered the *Terminal from
userdata, so they now simply forward it to the Go handler. This
lets callers define callbacks inline in NewTerminal without any
pre-declaration workaround.

+42 -37
+1 -1
doc.go
··· 32 32 // 33 33 // term, _ := libghostty.NewTerminal( 34 34 // libghostty.WithSize(80, 24), 35 - // libghostty.WithWritePty(func(data []byte) { 35 + // libghostty.WithWritePty(func(_ *libghostty.Terminal, data []byte) { 36 36 // os.Stdout.Write(data) 37 37 // }), 38 38 // )
+6 -9
examples/effects/main.go
··· 16 16 // Bell counter, captured by the bell handler closure. 17 17 bellCount := 0 18 18 19 - // We declare term here so the title_changed closure can capture it. 20 - var term *ghostty.Terminal 21 - 22 - var err error 23 - term, err = ghostty.NewTerminal( 19 + term, err := ghostty.NewTerminal( 24 20 ghostty.WithSize(80, 24), 25 21 26 22 // write_pty: called when the terminal writes data back (e.g. query responses). 27 - ghostty.WithWritePty(func(data []byte) { 23 + ghostty.WithWritePty(func(_ *ghostty.Terminal, data []byte) { 28 24 fmt.Printf("write_pty: %d bytes: %q\n", len(data), data) 29 25 }), 30 26 31 27 // bell: called on BEL (0x07). 32 - ghostty.WithBell(func() { 28 + ghostty.WithBell(func(_ *ghostty.Terminal) { 33 29 bellCount++ 34 30 fmt.Printf("bell: count=%d\n", bellCount) 35 31 }), 36 32 37 33 // title_changed: called when the terminal title changes via OSC 0/2. 38 - ghostty.WithTitleChanged(func() { 39 - x, err := term.CursorX() 34 + // The terminal is passed directly as a parameter. 35 + ghostty.WithTitleChanged(func(t *ghostty.Terminal) { 36 + x, err := t.CursorX() 40 37 if err != nil { 41 38 log.Fatal(err) 42 39 }
+1 -1
kitty_graphics_test.go
··· 45 45 WithSize(80, 24), 46 46 // Install a WritePty handler so the terminal can send 47 47 // protocol responses (required for kitty graphics). 48 - WithWritePty(func(data []byte) {}), 48 + WithWritePty(func(_ *Terminal, _ []byte) {}), 49 49 ) 50 50 if err != nil { 51 51 t.Fatal(err)
+18 -10
terminal.go
··· 68 68 } 69 69 70 70 // WritePtyFn is called when the terminal writes data back to the pty 71 - // (e.g. query responses). The data is only valid for the call duration. 71 + // (e.g. query responses). The first parameter is the terminal that 72 + // triggered the effect. The data is only valid for the call duration. 72 73 // C: GhosttyTerminalWritePtyFn 73 - type WritePtyFn func(data []byte) 74 + type WritePtyFn func(t *Terminal, data []byte) 74 75 75 76 // BellFn is called when the terminal receives a BEL character (0x07). 77 + // The parameter is the terminal that triggered the effect. 76 78 // C: GhosttyTerminalBellFn 77 - type BellFn func() 79 + type BellFn func(t *Terminal) 78 80 79 81 // TitleChangedFn is called when the terminal title changes via OSC 0/2. 82 + // The parameter is the terminal that triggered the effect. 80 83 // C: GhosttyTerminalTitleChangedFn 81 - type TitleChangedFn func() 84 + type TitleChangedFn func(t *Terminal) 82 85 83 86 // EnquiryFn is called when the terminal receives ENQ (0x05). 87 + // The first parameter is the terminal that triggered the effect. 84 88 // Return the response bytes; nil or empty means no response. 85 89 // C: GhosttyTerminalEnquiryFn 86 - type EnquiryFn func() []byte 90 + type EnquiryFn func(t *Terminal) []byte 87 91 88 92 // XtversionFn is called for XTVERSION queries (CSI > q). 93 + // The first parameter is the terminal that triggered the effect. 89 94 // Return the version string; empty uses the default "libghostty". 90 95 // C: GhosttyTerminalXtversionFn 91 - type XtversionFn func() string 96 + type XtversionFn func(t *Terminal) string 92 97 93 98 // SizeFn is called for XTWINOPS size queries (CSI 14/16/18 t). 99 + // The first parameter is the terminal that triggered the effect. 94 100 // Return the size and true, or zero value and false to ignore the query. 95 101 // C: GhosttyTerminalSizeFn 96 - type SizeFn func() (SizeReportSize, bool) 102 + type SizeFn func(t *Terminal) (SizeReportSize, bool) 97 103 98 104 // ColorSchemeFn is called for color scheme queries (CSI ? 996 n). 105 + // The first parameter is the terminal that triggered the effect. 99 106 // Return the scheme and true, or zero value and false to ignore the query. 100 107 // C: GhosttyTerminalColorSchemeFn 101 - type ColorSchemeFn func() (ColorScheme, bool) 108 + type ColorSchemeFn func(t *Terminal) (ColorScheme, bool) 102 109 103 110 // DeviceAttributesFn is called for device attributes queries 104 - // (CSI c / CSI > c / CSI = c). Return the attributes and true, 111 + // (CSI c / CSI > c / CSI = c). The first parameter is the terminal 112 + // that triggered the effect. Return the attributes and true, 105 113 // or zero value and false to ignore the query. 106 114 // C: GhosttyTerminalDeviceAttributesFn 107 - type DeviceAttributesFn func() (DeviceAttributes, bool) 115 + type DeviceAttributesFn func(t *Terminal) (DeviceAttributes, bool) 108 116 109 117 // WithSize sets the terminal dimensions in cells. 110 118 // Both cols and rows must be greater than zero.
+8 -8
terminal_effect.go
··· 115 115 func goWritePtyTrampoline(_ C.GhosttyTerminal, userdata unsafe.Pointer, data *C.uint8_t, length C.size_t) { 116 116 t := terminalFromUserdata(userdata) 117 117 if t.onWritePty != nil { 118 - t.onWritePty(C.GoBytes(unsafe.Pointer(data), C.int(length))) 118 + t.onWritePty(t, C.GoBytes(unsafe.Pointer(data), C.int(length))) 119 119 } 120 120 } 121 121 ··· 123 123 func goBellTrampoline(_ C.GhosttyTerminal, userdata unsafe.Pointer) { 124 124 t := terminalFromUserdata(userdata) 125 125 if t.onBell != nil { 126 - t.onBell() 126 + t.onBell(t) 127 127 } 128 128 } 129 129 ··· 131 131 func goTitleChangedTrampoline(_ C.GhosttyTerminal, userdata unsafe.Pointer) { 132 132 t := terminalFromUserdata(userdata) 133 133 if t.onTitleChanged != nil { 134 - t.onTitleChanged() 134 + t.onTitleChanged(t) 135 135 } 136 136 } 137 137 ··· 141 141 if t.onEnquiry == nil { 142 142 return C.GhosttyString{} 143 143 } 144 - return t.effectString(t.onEnquiry()) 144 + return t.effectString(t.onEnquiry(t)) 145 145 } 146 146 147 147 //export goXtversionTrampoline ··· 150 150 if t.onXtversion == nil { 151 151 return C.GhosttyString{} 152 152 } 153 - return t.effectString([]byte(t.onXtversion())) 153 + return t.effectString([]byte(t.onXtversion(t))) 154 154 } 155 155 156 156 //export goSizeTrampoline ··· 159 159 if t.onSize == nil { 160 160 return C.bool(false) 161 161 } 162 - size, ok := t.onSize() 162 + size, ok := t.onSize(t) 163 163 if !ok { 164 164 return C.bool(false) 165 165 } ··· 176 176 if t.onColorScheme == nil { 177 177 return C.bool(false) 178 178 } 179 - scheme, ok := t.onColorScheme() 179 + scheme, ok := t.onColorScheme(t) 180 180 if !ok { 181 181 return C.bool(false) 182 182 } ··· 190 190 if t.onDeviceAttributes == nil { 191 191 return C.bool(false) 192 192 } 193 - attrs, ok := t.onDeviceAttributes() 193 + attrs, ok := t.onDeviceAttributes(t) 194 194 if !ok { 195 195 return C.bool(false) 196 196 }
+8 -8
terminal_opt_test.go
··· 69 69 70 70 func TestTerminalWithBell(t *testing.T) { 71 71 var bellCount int 72 - term, err := NewTerminal(WithSize(80, 24), WithBell(func() { 72 + term, err := NewTerminal(WithSize(80, 24), WithBell(func(_ *Terminal) { 73 73 bellCount++ 74 74 })) 75 75 if err != nil { ··· 98 98 defer term.Close() 99 99 100 100 var bellCount int 101 - term.SetEffectBell(func() { 101 + term.SetEffectBell(func(_ *Terminal) { 102 102 bellCount++ 103 103 }) 104 104 ··· 117 117 118 118 func TestTerminalWithWritePty(t *testing.T) { 119 119 var received []byte 120 - term, err := NewTerminal(WithSize(80, 24), WithWritePty(func(data []byte) { 120 + term, err := NewTerminal(WithSize(80, 24), WithWritePty(func(_ *Terminal, data []byte) { 121 121 received = append(received, data...) 122 122 })) 123 123 if err != nil { ··· 134 134 135 135 func TestTerminalWithTitleChanged(t *testing.T) { 136 136 var titleChanged int 137 - term, err := NewTerminal(WithSize(80, 24), WithTitleChanged(func() { 137 + term, err := NewTerminal(WithSize(80, 24), WithTitleChanged(func(_ *Terminal) { 138 138 titleChanged++ 139 139 })) 140 140 if err != nil { ··· 153 153 var received []byte 154 154 term, err := NewTerminal( 155 155 WithSize(80, 24), 156 - WithWritePty(func(data []byte) { 156 + WithWritePty(func(_ *Terminal, data []byte) { 157 157 received = append(received, data...) 158 158 }), 159 - WithEnquiry(func() []byte { 159 + WithEnquiry(func(_ *Terminal) []byte { 160 160 return []byte("hello") 161 161 }), 162 162 ) ··· 176 176 var received []byte 177 177 term, err := NewTerminal( 178 178 WithSize(80, 24), 179 - WithWritePty(func(data []byte) { 179 + WithWritePty(func(_ *Terminal, data []byte) { 180 180 received = append(received, data...) 181 181 }), 182 - WithXtversion(func() string { 182 + WithXtversion(func(_ *Terminal) string { 183 183 return "myterm 1.0" 184 184 }), 185 185 )