Added input and libc files, updated basic example

main
noah metz 2024-04-23 22:10:40 -06:00
parent 281f038f5f
commit 5032b04a47
7 changed files with 162 additions and 36 deletions

@ -1,23 +1,43 @@
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"git.metznet.ca/MetzNet/go-ncurses"
)
func main() {
err := ncurses.Init()
if err != nil {
panic(err)
}
ncurses.SetLocale(0, "")
input, input_active := ncurses.UTF8Listener(100, os.Stdin)
window := ncurses.InitScr.Load()()
os_sigs := make(chan os.Signal, 1)
signal.Notify(os_sigs, syscall.SIGINT, syscall.SIGABRT)
x := ncurses.GetMaxX.Load()(window)
y := ncurses.GetMaxY.Load()(window)
window := ncurses.InitScr()
ret := ncurses.IdlOK(window, true)
if ret != 0 {
panic(ret)
}
ret = ncurses.ScrollOk(window, true)
if ret != 0 {
panic(ret)
}
ncurses.WRefresh(window)
fmt.Printf("%d x %d\n", x, y)
active := true
for active {
select {
case bytes := <-input:
ncurses.WAddStr(window, string(bytes))
ncurses.WRefresh(window)
case <-os_sigs:
active = false
}
}
ncurses.EndWin.Load()()
ncurses.EndWin()
input_active.Store(false)
close(input)
}

@ -2,7 +2,6 @@ module git.metznet.ca/MetzNet/go-ncurses
go 1.22.2
require (
github.com/ebitengine/purego v0.7.1 // indirect
golang.org/x/sys v0.7.0 // indirect
)
require github.com/ebitengine/purego v0.7.1
require golang.org/x/sys v0.7.0 // indirect

@ -0,0 +1,41 @@
package ncurses
import (
"os"
"sync/atomic"
)
func bitmatch(b byte, pattern byte, length int) bool {
mask := ^(byte(1 << (8 - length)) - 1)
return (b ^ pattern) & mask == 0
}
func UTF8Listen(file *os.File, channel chan []byte, active *atomic.Bool) {
b := [4]byte{}
for active.Load() {
file.Read(b[0:1])
if bitmatch(b[0], 0b00000000, 1) {
channel <- b[0:1]
} else if bitmatch(b[0], 0b11000000, 3) {
file.Read(b[1:2])
channel <- b[0:2]
} else if bitmatch(b[0], 0b11100000, 4) {
file.Read(b[1:3])
channel <- b[0:3]
} else if bitmatch(b[0], 0b11110000, 5) {
file.Read(b[1:4])
channel <- b[0:4]
}
}
}
// To cleanup, set active to false then close the channel
func UTF8Listener(buffer int, file *os.File) (chan []byte, *atomic.Bool) {
channel := make(chan []byte, buffer)
active := new(atomic.Bool)
active.Store(true)
go UTF8Listen(file, channel, active)
return channel, active
}

@ -0,0 +1,23 @@
package ncurses
import (
"github.com/ebitengine/purego"
)
var libc uintptr = 0
func libcFunction[T any](name string) T {
if libc == 0 {
var err error
libc, err = purego.Dlopen(LIBC_PATH, purego.RTLD_GLOBAL | purego.RTLD_NOW)
if err != nil {
panic(err)
}
}
var tmp = new(T)
purego.RegisterLibFunc(tmp, libc, name)
return *tmp
}
type setlocaleFP func(category int, locale string)
var SetLocale = libcFunction[setlocaleFP]("setlocale")

@ -1,24 +1,21 @@
package ncurses
import (
"sync/atomic"
"github.com/ebitengine/purego"
)
var ncurses atomic.Value
var ncurses uintptr = 0
func ncursesFunction[T any](name string) T {
if ncurses.Load() == nil {
lib, err := purego.Dlopen(LIBRARY_PATH, purego.RTLD_GLOBAL | purego.RTLD_LAZY)
if ncurses == 0 {
var err error
ncurses, err = purego.Dlopen(LIBRARY_PATH, purego.RTLD_GLOBAL | purego.RTLD_LAZY)
if err != nil {
panic(err)
}
ncurses.CompareAndSwap(nil, lib)
}
var tmp = new(T)
purego.RegisterLibFunc(tmp, ncurses.Load().(uintptr), name)
purego.RegisterLibFunc(tmp, ncurses, name)
return *tmp
}
@ -51,5 +48,31 @@ var WAddNStr = ncursesFunction[waddstrFP]("waddnstr")
var GetMaxY = ncursesFunction[winFP]("getmaxy")
var GetMaxX = ncursesFunction[winFP]("getmaxx")
type mvwaddstrFP func(window Window, x, y int, str string) int
type mvwaddstrFP func(window Window, y, x int, str string) int
var MvWAddStr = ncursesFunction[mvwaddstrFP]("mvwaddstr")
type mvwaddchFP func(window Window, y, x int, char rune) int
var MvWAddCh = ncursesFunction[mvwaddchFP]("mvwaddch")
type waddchFP func(window Window, char rune) int
var WAddCh = ncursesFunction[waddchFP]("waddch")
type init_colorFP func(color, r, g, b int16) int
var InitColor = ncursesFunction[init_colorFP]("init_color")
type init_pairFP func(pair, fg, bg int16) int
var InitPair = ncursesFunction[init_pairFP]("init_pair")
var StartColor = ncursesFunction[voidFP]("start_color")
type checkFP func() bool
var HasColors = ncursesFunction[checkFP]("has_colors")
type setflagFP func(window Window, bf bool) int
var ClearOK = ncursesFunction[setflagFP]("clearok")
var IdlOK = ncursesFunction[setflagFP]("idlok")
var ScrollOk = ncursesFunction[setflagFP]("scrollok")
type wscrlFP func(window Window, n int) int
var WScrl = ncursesFunction[wscrlFP]("wscrl")

@ -1,3 +1,4 @@
package ncurses
const LIBRARY_PATH = "libncurses.dylib"
const LIBC_PATH = "libSystem.B.dylib"

@ -5,39 +5,58 @@ import (
)
func StartTest(t *testing.T) Window {
err := Init()
if err != nil {
t.Fatalf("Init err - %s", err)
}
window := InitScr.Load()()
window := InitScr()
return window
}
func EndTest(t *testing.T) {
ret := EndWin.Load()()
ret := EndWin()
if ret != 0 {
t.Fatalf("EndWin result - 0x%x", ret)
t.Fatalf("EndWin result - 0x%02x", ret)
}
}
func TestInitScr(t *testing.T) {
window := StartTest(t)
t.Logf("InitScr result - 0x%x", window)
StartTest(t)
EndTest(t)
}
func TestNewWin(t *testing.T) {
StartTest(t)
window := NewWin.Load()(10, 10, 0, 0)
window := NewWin(10, 10, 0, 0)
t.Logf("NewWin result - 0x%x", window)
ret := DelWin.Load()(window)
ret := DelWin(window)
if ret != 0 {
t.Fatalf("DelWin result - 0x%x", ret)
t.Fatalf("DelWin result - 0x%02x", ret)
}
EndTest(t)
}
func TestColors(t *testing.T) {
StartTest(t)
ret := StartColor()
if ret != 0 {
t.Fatalf("StartColor result - 0x%02x", ret)
}
ret = InitColor(0, 1000, 0, 0)
if ret != 0 {
t.Fatalf("InitColor result - 0x%02x", ret)
}
ret = InitColor(1, 0, 1000, 0)
if ret != 0 {
t.Fatalf("InitColor result - 0x%02x", ret)
}
ret = InitPair(1, 0, 1)
if ret != 0 {
t.Fatalf("InitPair result - 0x%02x", ret)
}
EndTest(t)
}