Compare commits

..

No commits in common. "master" and "v0.0.1" have entirely different histories.

4 changed files with 30 additions and 330 deletions

View File

@ -1,11 +1,27 @@
// Copyright 2025 WIT.COM Inc Licensed GPL 3.0 // Copyright 2025 WIT.COM Inc Licensed GPL 3.0
// you can replace all of COBOL with this amount of GO
// ah yes, COBOL. what an ancient throwback. for those that know // ah yes, COBOL. what an ancient throwback. for those that know
// then you know exactly what is in this file. For those that don't, here it is: // then you know exactly what is in this file. For those that don't, here it is:
// All this does is output human readable text formatted to be viewable on // All this does is output human readable text formatted to be viewable on
// a console with a fixed with font. AKA: a typerwriter. Which is exactly // a console with a fixed with font. AKA: a typerwriter. Which is exactly
// what COBOL did in the 1970's (60s? notsure). And the 80s. // what COBOL did in the 1970's (60s? notsure) And the 80s.
// Perl, before GO, was great for this kinda thing. GO with // So, you want to dump out stuff on the console. Let's see. Something like
// protobuffers is even better
/*
forge --favorites
go.wit.com/apps/myapp v0.2.0 (installed)
go.wit.com/lib/somethingfun v0.0.7 (not downloaded)
*/
// anyway, you get the idea. This is also called COBOL because it does
// truncate every line output to the columns you see with stty -a
// my monitor is huge, so it's not going to work at 80x24. 160x48 is better
// actually, I'd predict some of these will probably end up 240 wide
// long live good eyesight and 4K monitors!
// TODO: fix this to truncate with stty cols width

View File

@ -4,7 +4,6 @@ package cobol
import ( import (
"fmt" "fmt"
"strings"
) )
// TODO: make this more generic // TODO: make this more generic
@ -14,44 +13,7 @@ import (
// sizes := []int{40, 12, 6, 12, 16, 16, 16, 12, 12, 8} // sizes := []int{40, 12, 6, 12, 16, 16, 16, 12, 12, 8}
// log.Info(standardTableSize10(sizes, args)) // log.Info(standardTableSize10(sizes, args))
// returns the line and the Sprintf fmt string
func StandardTableRow(sizes []int, args []string) (string, string) {
var fmts []string
var parts []string
for i, si := range sizes {
var cell string
var sfmt string
if si < 0 {
sfmt = "%-s"
} else if si == 0 {
sfmt = "%-8.8s"
} else {
sfmt = "%-" + fmt.Sprintf("%d", si) + "." + fmt.Sprintf("%d", si) + "s "
}
fmts = append(fmts, sfmt)
if len(args) > i {
val := args[i]
cell = fmt.Sprintf(sfmt, val)
parts = append(parts, cell)
} else {
break
}
}
// todo: change pad based on total size(?)
line := strings.Join(parts, " ")
var small int
if len(line) > WIDTH {
small = WIDTH
} else {
small = len(line) - 3
}
return line[0:small], strings.Join(fmts, " ")
}
func StandardTableSize5(sizes []int, args []string) string { func StandardTableSize5(sizes []int, args []string) string {
WIDTH, _ := getTerminalWidth()
var s string var s string
for i, si := range sizes { for i, si := range sizes {
if si == 0 { if si == 0 {
@ -70,13 +32,19 @@ func StandardTableSize5(sizes []int, args []string) string {
arg4 := args[3] arg4 := args[3]
arg5 := args[4] arg5 := args[4]
all := fmt.Sprintf(s, arg1, arg2, arg3, arg4, arg5) return fmt.Sprintf(s, arg1, arg2, arg3, arg4, arg5)
return all[0:WIDTH]
} }
/*
func standardTable10(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 string) string {
args := []string{arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10}
sizes := []int{40, 12, 6, 12, 16, 16, 16, 12, 12, 8}
return standardTableSize10(sizes, args)
}
*/
func StandardTableSize10(sizes []int, args []string) string { func StandardTableSize10(sizes []int, args []string) string {
WIDTH, _ := getTerminalWidth()
// log.Info("WIDTH IS", WIDTH)
var s string var s string
for i, si := range sizes { for i, si := range sizes {
if si == 0 { if si == 0 {
@ -100,12 +68,5 @@ func StandardTableSize10(sizes []int, args []string) string {
arg9 := args[8] arg9 := args[8]
arg10 := args[9] arg10 := args[9]
all := fmt.Sprintf(s, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) return fmt.Sprintf(s, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)
var small int
if len(all) > WIDTH {
small = WIDTH
} else {
small = len(all) - 3
}
return all[0:small]
} }

View File

@ -1,227 +0,0 @@
// Copyright 2025 WIT.COM Inc Licensed GPL 3.0
package cobol
import (
"fmt"
"os"
"time"
"go.wit.com/lib/gui/shell"
"go.wit.com/lib/protobuf/guipb"
"go.wit.com/log"
"google.golang.org/protobuf/types/known/anypb"
"google.golang.org/protobuf/types/known/timestamppb"
"google.golang.org/protobuf/types/known/wrapperspb"
)
func PrintTable(pb *guipb.Table) {
// log.Info("print PB here")
if pb.Grid == nil {
// log.Info("grid = nil")
} else {
// log.Info("grid.Id =", pb.Grid.Id)
}
var h int = 0
var w int = 0
var HEIGHT int
if pb.Height == 0 {
HEIGHT = 4
}
// log.Info("pb.Height", pb.Height, HEIGHT)
var args []string
var sizes []int
for _, name := range pb.Order {
arg, attr, tmp := getColAttr(pb, name)
if attr == nil {
continue
}
HEIGHT = tmp
args = append(args, arg)
if attr.Width == 0 {
sizes = append(sizes, 8)
} else {
sizes = append(sizes, int(attr.Width))
}
}
// sizes = []int{24, 5, 8, 32, 13, 4, 4, 4, 4}
header, _ := StandardTableRow(sizes, args)
log.Info(header)
for i := range HEIGHT {
var cells []string
for _, name := range pb.Order {
if val, ok := getAnyCell(pb, name, int(i)); ok {
h += 1
cells = append(cells, val)
continue
}
if val, ok := getTableCell(pb, name, int(i)); ok {
// log.Info("tree: CELL GOOD", pb.Title, name, w, h, val)
h += 1
cells = append(cells, val)
} else {
log.Info("tree: CELL FAIL", pb.Title, name, w, h, val)
cells = append(cells, "err")
}
}
line, fmtline := StandardTableRow(sizes, cells)
if os.Getenv("TABLEPB_VERBOSE") == "true" {
line += "FMT: " + fmtline
}
log.Info(line)
}
}
func makeGridLabel(pb *guipb.Widget, w int, h int) {
log.Info("MAKE GRID LABEL", w, h, pb.Name)
}
func extractInt64(anyVal *anypb.Any) (int64, error) {
val := &wrapperspb.Int64Value{}
if err := anyVal.UnmarshalTo(val); err != nil {
return 0, err
}
return val.Value, nil
}
func getTableCell(t *guipb.Table, name string, row int) (string, bool) {
// find the Column that matches the "name"
for _, r := range t.StringCols {
if name != r.Header.Name {
// log.Info("skip string row:", r.Header.Name, "!=", name)
continue
}
// log.Info("Cell value:", r.Vals[row])
return r.Vals[row], true
}
for _, r := range t.ButtonCols {
if name != r.Header.Name {
// log.Info("skip string row:", r.Header.Name, "!=", name)
continue
}
// log.Info("Cell value:", r.Vals[row])
return r.Vals[row], true
}
for _, r := range t.IntCols {
if name != r.Header.Name {
// log.Info("skip string row:", r.Header.Name, "!=", name)
continue
}
return fmt.Sprintf("%d", r.Vals[row]), true
}
for _, r := range t.TimeCols {
if name != r.Header.Name {
// log.Info("skip sint row:", r.Header.Name, "!=", name)
continue
}
cellTime := r.Vals[row]
s := shell.FormatDuration(time.Since(cellTime.AsTime()))
return s, true
}
for _, r := range t.AnyCols {
if name != r.Header.Name {
// log.Info("skip sint row:", r.Header.Name, "!=", name)
continue
}
// cellTime := r.Vals[row]
// s := shell.FormatDuration(time.Since(cellTime.AsTime()))
return "fixme", true
}
return "", false
}
func getAnyCell(t *guipb.Table, name string, row int) (string, bool) {
for _, col := range t.AnyCols {
if name != col.Header.Name {
// log.Info("skip sint row:", r.Header.Name, "!=", name)
continue
}
anyVal := col.Vals[row]
switch col.Attr.Type {
case guipb.ColAttr_STRING:
// return col.Vals[row] true
// Assume 'anyVal' is an element from your r.Vals slice
var stringValue wrapperspb.StringValue
if err := anyVal.UnmarshalTo(&stringValue); err == nil {
// It's a string, now convert it back to a native Go string
goString := stringValue.GetValue()
// fmt.Printf("Successfully unpacked string: %s\n", goString)
return goString, true
}
case guipb.ColAttr_INT:
var finalInt int32
// 1. Check if the Any contains an Int32Value
if anyVal.MessageIs(&wrapperspb.Int32Value{}) {
var intValue wrapperspb.Int32Value
// 2. Unmarshal into the wrapper
if err := anyVal.UnmarshalTo(&intValue); err == nil {
// 3. Get the native Go int32 from the wrapper
finalInt = intValue.GetValue()
}
}
return fmt.Sprintf("%d", finalInt), true
case guipb.ColAttr_DURATION:
case guipb.ColAttr_TIME:
var sout string
var tsProto timestamppb.Timestamp
if err := anyVal.UnmarshalTo(&tsProto); err == nil {
// It's a timestamp, now convert it back to a Go time.Time
goTime := tsProto.AsTime()
// fmt.Printf("Successfully unpacked timestamp: %v\n", goTime)
sout = shell.FormatDuration(time.Since(goTime))
return sout, true
}
return "", false
default:
log.Info("cell unhandled type", col.Attr.Type)
}
// cellTime := r.Vals[row]
// s := shell.FormatDuration(time.Since(cellTime.AsTime()))
return "fixme", true
}
return "", false
}
func getColAttr(t *guipb.Table, name string) (string, *guipb.ColAttr, int) {
// find the Column that matches the "name"
for _, r := range t.StringCols {
if name != r.Header.Name {
continue
}
return r.Header.Name, r.Attr, len(r.Vals)
}
for _, r := range t.ButtonCols {
if name != r.Header.Name {
// log.Info("skip string row:", r.Header.Name, "!=", name)
continue
}
return r.Header.Name, r.Attr, len(r.Vals)
}
for _, r := range t.IntCols {
if name != r.Header.Name {
// log.Info("skip string row:", r.Header.Name, "!=", name)
continue
}
return r.Header.Name, r.Attr, len(r.Vals)
}
for _, r := range t.TimeCols {
if name != r.Header.Name {
// log.Info("skip sint row:", r.Header.Name, "!=", name)
continue
}
return r.Header.Name, r.Attr, len(r.Vals)
}
for _, r := range t.AnyCols {
if name != r.Header.Name {
// log.Info("skip sint row:", r.Header.Name, "!=", name)
continue
}
return r.Header.Name, r.Attr, len(r.Vals)
}
return "", nil, 0
}

View File

@ -1,50 +0,0 @@
package cobol
import (
"os"
"strings"
"unicode"
"go.wit.com/log"
"golang.org/x/term"
)
var WIDTH int = 120
// getTerminalWidth returns the width of the active terminal.
// If the output is not an interactive terminal (e.g., it's being piped to a file
// or another command), it returns a default width and false.
func getTerminalWidth() (int, bool) {
// term.IsTerminal checks if the given file descriptor is connected to a terminal.
// We use os.Stdout.Fd() to check the standard output.
if term.IsTerminal(int(os.Stdout.Fd())) {
var err error
// term.GetSize returns the dimensions of the given terminal.
WIDTH, _, err = term.GetSize(int(os.Stdout.Fd()))
if err != nil {
// If we can't get the size for some reason, fall back to the default.
log.Printf("could not get terminal size: %v", err)
return WIDTH, false
}
return WIDTH, true
}
// If it's not a terminal, return the default width.
return WIDTH, false
}
// like the perl Chomp but with the terminal width
func TerminalChomp(cut string) string {
i, _ := getTerminalWidth()
// log.Info("cobol.TerminalCut() at ", i)
// TrimRightFunc removes all trailing runes r from the string s that satisfy f(r).
// unicode.IsSpace reports whether the rune is a space character.
cut = strings.TrimRightFunc(cut, unicode.IsSpace)
if i >= len(cut) {
return cut
} else {
return log.Sprintf("%s", cut[0:i])
}
}