From: Banana Date: Sun, 8 Jan 2023 00:02:42 +0000 (+0100) Subject: a go cli and tui client. Not really ready yet X-Git-Tag: 1.1~17 X-Git-Url: http://91.132.146.200/gitweb/?a=commitdiff_plain;h=4c68910a2b3e88a95c18066523998341739e9999;p=scientia.git a go cli and tui client. Not really ready yet --- diff --git a/client/go-cli/README b/client/go-cli/README new file mode 100644 index 0000000..f3f6d65 --- /dev/null +++ b/client/go-cli/README @@ -0,0 +1,9 @@ +This is a terminal cli client written in go to be used with scientia +https://://www.bananas-playground.net/projekt/scientia + +!WARNING! +This is a very simple, with limited experience written, go program. +Use at own risk and feel free to improve. + +Howto build: +Nothing special, just go build -o scientia-cli diff --git a/client/go-cli/scientia-cli.go b/client/go-cli/scientia-cli.go new file mode 100644 index 0000000..9ce1858 --- /dev/null +++ b/client/go-cli/scientia-cli.go @@ -0,0 +1,254 @@ +package main + +import ( + "errors" + "fmt" + "log" + "math/rand" + "os" + "flag" + "gopkg.in/yaml.v2" + "net/http" + "io/ioutil" + "bytes" + "mime/multipart" + "encoding/json" +) + +/** + * scientia + * + * Copyright 2022 Johannes Keßler + * + * https://www.bananas-playground.net/projekt/scientia/ + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the COMMON DEVELOPMENT AND DISTRIBUTION LICENSE + * + * You should have received a copy of the + * COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + * along with this program. If not, see http://www.sun.com/cddl/cddl.html + */ + +const website = "https://www.bananas-playground.net/projekt/scientia" +const version = "1.0" +// used for non-existing default config +const letters = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-_" + +// command line parameters +var optsVerbose bool +var optsCreateConfig bool +var optsDebug bool + +// config +var cfg Config +// config file struct +type Config struct { + Endpoint struct { + Host string `yaml:"host"` + Secret string `yaml:"secret"` + } `yaml:"endpoint"` +} + +// response json struct +type Response struct { + Message string `json:"message"` + Status int `json:"status"` +} + +/** + * Main + */ +func main() { + + // parse commandline parameters + flag.BoolVar(&optsVerbose, "verbose", false, "Produce verbose output") + flag.BoolVar(&optsCreateConfig, "create-config-file", false, "Create default config file") + flag.BoolVar(&optsDebug, "debug", false, "Print debug infos") + flag.Parse() + if optsDebug { + fmt.Println("verbose:", optsVerbose) + fmt.Println("create-config-file:", optsCreateConfig) + fmt.Println("debug:", optsDebug) + } + + // load the config and populate Config + loadConfig() + + // get the payload + payload := getInput() + if optsDebug { log.Println(payload) } + + // do the upload and get the response + responseString := uploadCall(payload) + response := Response{} + json.Unmarshal([]byte(responseString), &response) + + // print the result and link to the pasty + fmt.Printf("Status: %d\n", response.Status) + fmt.Printf("Message: %s\n", response.Message) +} + + + + +/** + * Check and display error with additional message + */ +func errorCheck(e error, msg string) { + if e != nil { + log.Fatal(msg,e) + } +} + +/** + * just a random string + */ +func randStringBytes(n int) string { + b := make([]byte, n) + for i := range b { + b[i] = letters[rand.Intn(len(letters))] + } + return string(b) +} + +/** + * load or even create a default config + * $HOME/.scientia.yaml + */ +func loadConfig() { + homeDir, err := os.UserHomeDir() + errorCheck(err, "No $HOME directory available?") + if optsVerbose { log.Printf("Your $HOME: %s \n", homeDir) } + + var configFile = homeDir + "/.scientia.yaml" + + if _, err := os.Stat(configFile); errors.Is(err, os.ErrNotExist) { + log.Printf("Config file not found: %s \n", configFile) + + if optsCreateConfig { + log.Printf("Creating new default config file: %s \n", configFile) + + newConfig, err := os.Create(configFile) + errorCheck(err, "Can not create config file!") + defer newConfig.Close() + + + _, err = fmt.Fprintf(newConfig, "# scientia go client config file.\n") + errorCheck(err, "Can not write to new config file") + fmt.Fprintf(newConfig, "# See %s for more details.\n", website) + fmt.Fprintf(newConfig, "# Version: %s\n", version) + fmt.Fprintf(newConfig, "endpoint:\n") + fmt.Fprintf(newConfig, " host: http://your-scientia-endpoi.nt\n") + fmt.Fprintf(newConfig, " secret: %s\n", randStringBytes(50)) + + log.Fatalf("New default config file created: - %s - Edit and launch again!",configFile) + } + } + + existingConfigFile, err := os.Open(configFile) + errorCheck(err, "Can not open config file") + defer existingConfigFile.Close() + if optsVerbose { log.Printf("Reading config file: %s \n", configFile) } + + var decoder = yaml.NewDecoder(existingConfigFile) + err = decoder.Decode(&cfg) + errorCheck(err, "Can not decode config file") + + if cfg.Endpoint.Host == "" || cfg.Endpoint.Secret == "" { + log.Fatal("Empty config?") + } + + if optsDebug { + log.Println(cfg.Endpoint.Host) + log.Println(cfg.Endpoint.Secret) + } +} + +/** + * Do a http POST call to the defined endpoint + * and upload the payload + * Return response body as string + */ +func uploadCall(payload string) string { + + if optsVerbose { log.Println("Starting to upload data") } + if optsDebug { log.Println(payload) } + if len(payload) == 0 { + log.Fatal("Nothing provided to upload") + } + + // Buffer to store our request body as bytes + var requestBody bytes.Buffer + + // Create a multipart writer + multiPartWriter := multipart.NewWriter(&requestBody) + + // file field + fileWriter, err := multiPartWriter.CreateFormFile("pasty", "pastyfile") + errorCheck(err, "Can not create form file field") + fileWriter.Write([]byte(payload)) + + dlField, err := multiPartWriter.CreateFormField("dl") + errorCheck(err, "Can not create form dl field") + dlField.Write([]byte(cfg.Endpoint.Secret)) + + multiPartWriter.Close() + + req, err := http.NewRequest(http.MethodPost, cfg.Endpoint.Host, &requestBody) + errorCheck(err, "Can not create http request") + // We need to set the content type from the writer, it includes necessary boundary as well + req.Header.Set("Content-Type", multiPartWriter.FormDataContentType()) + req.Header.Set("User-Agent", "scientiaAgent/1.0"); + + // Do the request + client := &http.Client{} + response, err := client.Do(req) + errorCheck(err, "POST request failed") + + responseBody, err := ioutil.ReadAll(response.Body) + errorCheck(err, "Can not read response body") + + if optsVerbose { log.Println("Request done") } + if optsDebug { + log.Printf("Response status code: %d\n",response.StatusCode) + log.Printf("Response headers: %#v\n", response.Header) + log.Println(string(responseBody)) + } + + return string(responseBody) +} + +/** + * check if file is provided as commandline argument + * or piped into + * return the read data as string + */ +func getInput() string { + if optsVerbose { log.Println("Getting input") } + + var inputString string + + if filename := flag.Arg(0); filename != "" { + if optsVerbose { log.Println("Read from file argument") } + + bytes, err := os.ReadFile(filename) + errorCheck(err, "Error opening file") + inputString = string(bytes) + } else { + stat, _ := os.Stdin.Stat() + if (stat.Mode() & os.ModeCharDevice) == 0 { + if optsVerbose { log.Println("data is being piped") } + + bytes, _ := ioutil.ReadAll(os.Stdin) + inputString = string(bytes) + } + } + + if len(inputString) == 0 { + log.Fatal("Nothing provided to upload") + } + + return inputString +} diff --git a/client/go-client/README b/client/go-client/README deleted file mode 100644 index 7c64d47..0000000 --- a/client/go-client/README +++ /dev/null @@ -1,9 +0,0 @@ -This is a client written in go to be used with scientia -https://://www.bananas-playground.net/projekt/scientia - -!WARNING! -This is a very simple, with limited experience written, go program. -Use at own risk and feel free to improve. - -Howto build: -Nothing special, just go build -o scientia \ No newline at end of file diff --git a/client/go-client/_scientia.go b/client/go-client/_scientia.go deleted file mode 100644 index 9ce1858..0000000 --- a/client/go-client/_scientia.go +++ /dev/null @@ -1,254 +0,0 @@ -package main - -import ( - "errors" - "fmt" - "log" - "math/rand" - "os" - "flag" - "gopkg.in/yaml.v2" - "net/http" - "io/ioutil" - "bytes" - "mime/multipart" - "encoding/json" -) - -/** - * scientia - * - * Copyright 2022 Johannes Keßler - * - * https://www.bananas-playground.net/projekt/scientia/ - * - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the COMMON DEVELOPMENT AND DISTRIBUTION LICENSE - * - * You should have received a copy of the - * COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 - * along with this program. If not, see http://www.sun.com/cddl/cddl.html - */ - -const website = "https://www.bananas-playground.net/projekt/scientia" -const version = "1.0" -// used for non-existing default config -const letters = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-_" - -// command line parameters -var optsVerbose bool -var optsCreateConfig bool -var optsDebug bool - -// config -var cfg Config -// config file struct -type Config struct { - Endpoint struct { - Host string `yaml:"host"` - Secret string `yaml:"secret"` - } `yaml:"endpoint"` -} - -// response json struct -type Response struct { - Message string `json:"message"` - Status int `json:"status"` -} - -/** - * Main - */ -func main() { - - // parse commandline parameters - flag.BoolVar(&optsVerbose, "verbose", false, "Produce verbose output") - flag.BoolVar(&optsCreateConfig, "create-config-file", false, "Create default config file") - flag.BoolVar(&optsDebug, "debug", false, "Print debug infos") - flag.Parse() - if optsDebug { - fmt.Println("verbose:", optsVerbose) - fmt.Println("create-config-file:", optsCreateConfig) - fmt.Println("debug:", optsDebug) - } - - // load the config and populate Config - loadConfig() - - // get the payload - payload := getInput() - if optsDebug { log.Println(payload) } - - // do the upload and get the response - responseString := uploadCall(payload) - response := Response{} - json.Unmarshal([]byte(responseString), &response) - - // print the result and link to the pasty - fmt.Printf("Status: %d\n", response.Status) - fmt.Printf("Message: %s\n", response.Message) -} - - - - -/** - * Check and display error with additional message - */ -func errorCheck(e error, msg string) { - if e != nil { - log.Fatal(msg,e) - } -} - -/** - * just a random string - */ -func randStringBytes(n int) string { - b := make([]byte, n) - for i := range b { - b[i] = letters[rand.Intn(len(letters))] - } - return string(b) -} - -/** - * load or even create a default config - * $HOME/.scientia.yaml - */ -func loadConfig() { - homeDir, err := os.UserHomeDir() - errorCheck(err, "No $HOME directory available?") - if optsVerbose { log.Printf("Your $HOME: %s \n", homeDir) } - - var configFile = homeDir + "/.scientia.yaml" - - if _, err := os.Stat(configFile); errors.Is(err, os.ErrNotExist) { - log.Printf("Config file not found: %s \n", configFile) - - if optsCreateConfig { - log.Printf("Creating new default config file: %s \n", configFile) - - newConfig, err := os.Create(configFile) - errorCheck(err, "Can not create config file!") - defer newConfig.Close() - - - _, err = fmt.Fprintf(newConfig, "# scientia go client config file.\n") - errorCheck(err, "Can not write to new config file") - fmt.Fprintf(newConfig, "# See %s for more details.\n", website) - fmt.Fprintf(newConfig, "# Version: %s\n", version) - fmt.Fprintf(newConfig, "endpoint:\n") - fmt.Fprintf(newConfig, " host: http://your-scientia-endpoi.nt\n") - fmt.Fprintf(newConfig, " secret: %s\n", randStringBytes(50)) - - log.Fatalf("New default config file created: - %s - Edit and launch again!",configFile) - } - } - - existingConfigFile, err := os.Open(configFile) - errorCheck(err, "Can not open config file") - defer existingConfigFile.Close() - if optsVerbose { log.Printf("Reading config file: %s \n", configFile) } - - var decoder = yaml.NewDecoder(existingConfigFile) - err = decoder.Decode(&cfg) - errorCheck(err, "Can not decode config file") - - if cfg.Endpoint.Host == "" || cfg.Endpoint.Secret == "" { - log.Fatal("Empty config?") - } - - if optsDebug { - log.Println(cfg.Endpoint.Host) - log.Println(cfg.Endpoint.Secret) - } -} - -/** - * Do a http POST call to the defined endpoint - * and upload the payload - * Return response body as string - */ -func uploadCall(payload string) string { - - if optsVerbose { log.Println("Starting to upload data") } - if optsDebug { log.Println(payload) } - if len(payload) == 0 { - log.Fatal("Nothing provided to upload") - } - - // Buffer to store our request body as bytes - var requestBody bytes.Buffer - - // Create a multipart writer - multiPartWriter := multipart.NewWriter(&requestBody) - - // file field - fileWriter, err := multiPartWriter.CreateFormFile("pasty", "pastyfile") - errorCheck(err, "Can not create form file field") - fileWriter.Write([]byte(payload)) - - dlField, err := multiPartWriter.CreateFormField("dl") - errorCheck(err, "Can not create form dl field") - dlField.Write([]byte(cfg.Endpoint.Secret)) - - multiPartWriter.Close() - - req, err := http.NewRequest(http.MethodPost, cfg.Endpoint.Host, &requestBody) - errorCheck(err, "Can not create http request") - // We need to set the content type from the writer, it includes necessary boundary as well - req.Header.Set("Content-Type", multiPartWriter.FormDataContentType()) - req.Header.Set("User-Agent", "scientiaAgent/1.0"); - - // Do the request - client := &http.Client{} - response, err := client.Do(req) - errorCheck(err, "POST request failed") - - responseBody, err := ioutil.ReadAll(response.Body) - errorCheck(err, "Can not read response body") - - if optsVerbose { log.Println("Request done") } - if optsDebug { - log.Printf("Response status code: %d\n",response.StatusCode) - log.Printf("Response headers: %#v\n", response.Header) - log.Println(string(responseBody)) - } - - return string(responseBody) -} - -/** - * check if file is provided as commandline argument - * or piped into - * return the read data as string - */ -func getInput() string { - if optsVerbose { log.Println("Getting input") } - - var inputString string - - if filename := flag.Arg(0); filename != "" { - if optsVerbose { log.Println("Read from file argument") } - - bytes, err := os.ReadFile(filename) - errorCheck(err, "Error opening file") - inputString = string(bytes) - } else { - stat, _ := os.Stdin.Stat() - if (stat.Mode() & os.ModeCharDevice) == 0 { - if optsVerbose { log.Println("data is being piped") } - - bytes, _ := ioutil.ReadAll(os.Stdin) - inputString = string(bytes) - } - } - - if len(inputString) == 0 { - log.Fatal("Nothing provided to upload") - } - - return inputString -} diff --git a/client/go-client/go.mod b/client/go-client/go.mod deleted file mode 100644 index bd776c7..0000000 --- a/client/go-client/go.mod +++ /dev/null @@ -1,28 +0,0 @@ -module scientia/go-client - -go 1.19 - -require ( - github.com/charmbracelet/bubbles v0.14.0 - github.com/charmbracelet/bubbletea v0.23.1 - github.com/charmbracelet/lipgloss v0.6.0 -) - -require ( - github.com/atotto/clipboard v0.1.4 // indirect - github.com/aymanbagabas/go-osc52 v1.0.3 // indirect - github.com/containerd/console v1.0.3 // indirect - github.com/lucasb-eyer/go-colorful v1.2.0 // indirect - github.com/mattn/go-isatty v0.0.16 // indirect - github.com/mattn/go-localereader v0.0.1 // indirect - github.com/mattn/go-runewidth v0.0.14 // indirect - github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect - github.com/muesli/cancelreader v0.2.2 // indirect - github.com/muesli/reflow v0.3.0 // indirect - github.com/muesli/termenv v0.13.0 // indirect - github.com/rivo/uniseg v0.2.0 // indirect - github.com/sahilm/fuzzy v0.1.0 // indirect - golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect - golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect - golang.org/x/text v0.3.7 // indirect -) diff --git a/client/go-client/go.sum b/client/go-client/go.sum deleted file mode 100644 index 45ebbf2..0000000 --- a/client/go-client/go.sum +++ /dev/null @@ -1,58 +0,0 @@ -github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= -github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= -github.com/aymanbagabas/go-osc52 v1.0.3 h1:DTwqENW7X9arYimJrPeGZcV0ln14sGMt3pHZspWD+Mg= -github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4= -github.com/charmbracelet/bubbles v0.14.0 h1:DJfCwnARfWjZLvMglhSQzo76UZ2gucuHPy9jLWX45Og= -github.com/charmbracelet/bubbles v0.14.0/go.mod h1:bbeTiXwPww4M031aGi8UK2HT9RDWoiNibae+1yCMtcc= -github.com/charmbracelet/bubbletea v0.21.0/go.mod h1:GgmJMec61d08zXsOhqRC/AiOx4K4pmz+VIcRIm1FKr4= -github.com/charmbracelet/bubbletea v0.23.1 h1:CYdteX1wCiCzKNUlwm25ZHBIc1GXlYFyUIte8WPvhck= -github.com/charmbracelet/bubbletea v0.23.1/go.mod h1:JAfGK/3/pPKHTnAS8JIE2u9f61BjWTQY57RbT25aMXU= -github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= -github.com/charmbracelet/lipgloss v0.5.0/go.mod h1:EZLha/HbzEt7cYqdFPovlqy5FZPj0xFhg5SaqxScmgs= -github.com/charmbracelet/lipgloss v0.6.0 h1:1StyZB9vBSOyuZxQUcUwGr17JmojPNm87inij9N3wJY= -github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk= -github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= -github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= -github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= -github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= -github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= -github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= -github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34= -github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= -github.com/muesli/cancelreader v0.2.0/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= -github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= -github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= -github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ= -github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= -github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= -github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs= -github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs= -github.com/muesli/termenv v0.13.0 h1:wK20DRpJdDX8b7Ek2QfhvqhRQFZ237RGRO0RQ/Iqdy0= -github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc= -github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI= -github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/client/go-client/scientia b/client/go-client/scientia deleted file mode 100755 index 2eacc3a..0000000 Binary files a/client/go-client/scientia and /dev/null differ diff --git a/client/go-client/scientia.go b/client/go-client/scientia.go deleted file mode 100644 index fc60015..0000000 --- a/client/go-client/scientia.go +++ /dev/null @@ -1,128 +0,0 @@ -package main - -import ( - "fmt" - "io" - "os" - - "github.com/charmbracelet/bubbles/list" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" -) - -const listHeight = 14 - -var ( - titleStyle = lipgloss.NewStyle().MarginLeft(2) - itemStyle = lipgloss.NewStyle().PaddingLeft(4) - selectedItemStyle = lipgloss.NewStyle().PaddingLeft(2).Foreground(lipgloss.Color("170")) - paginationStyle = list.DefaultStyles().PaginationStyle.PaddingLeft(4) - helpStyle = list.DefaultStyles().HelpStyle.PaddingLeft(4).PaddingBottom(1) - quitTextStyle = lipgloss.NewStyle().Margin(1, 0, 2, 4) -) - -type item string - -func (i item) FilterValue() string { return "" } - -type itemDelegate struct{} - -func (d itemDelegate) Height() int { return 1 } -func (d itemDelegate) Spacing() int { return 0 } -func (d itemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil } - -func (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) { - i, ok := listItem.(item) - if !ok { - return - } - - str := fmt.Sprintf("%d. %s", index+1, i) - - fn := itemStyle.Render - if index == m.Index() { - fn = func(s string) string { - return selectedItemStyle.Render("> " + s) - } - } - - fmt.Fprint(w, fn(str)) -} - -type model struct { - list list.Model - choice string - quitting bool -} - -func (m model) Init() tea.Cmd { - return nil -} - -func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - switch msg := msg.(type) { - case tea.WindowSizeMsg: - m.list.SetWidth(msg.Width) - return m, nil - - case tea.KeyMsg: - switch keypress := msg.String(); keypress { - case "ctrl+c": - m.quitting = true - return m, tea.Quit - - case "enter": - i, ok := m.list.SelectedItem().(item) - if ok { - m.choice = string(i) - } - return m, tea.Quit - } - } - - var cmd tea.Cmd - m.list, cmd = m.list.Update(msg) - return m, cmd -} - -func (m model) View() string { - if m.choice != "" { - return quitTextStyle.Render(fmt.Sprintf("%s? Sounds good to me.", m.choice)) - } - if m.quitting { - return quitTextStyle.Render("Not hungry? That’s cool.") - } - return "\n" + m.list.View() -} - -func main() { - items := []list.Item{ - item("Ramen"), - item("Tomato Soup"), - item("Hamburgers"), - item("Cheeseburgers"), - item("Currywurst"), - item("Okonomiyaki"), - item("Pasta"), - item("Fillet Mignon"), - item("Caviar"), - item("Just Wine"), - } - - const defaultWidth = 20 - - l := list.New(items, itemDelegate{}, defaultWidth, listHeight) - l.Title = "What do you want for dinner?" - l.SetShowStatusBar(false) - l.SetFilteringEnabled(false) - l.Styles.Title = titleStyle - l.Styles.PaginationStyle = paginationStyle - l.Styles.HelpStyle = helpStyle - - m := model{list: l} - - if _, err := tea.NewProgram(m).Run(); err != nil { - fmt.Println("Error running program:", err) - os.Exit(1) - } -} \ No newline at end of file diff --git a/client/go-tui/README b/client/go-tui/README new file mode 100644 index 0000000..3c22350 --- /dev/null +++ b/client/go-tui/README @@ -0,0 +1,9 @@ +This is a terminal tui client written in go to be used with scientia +https://://www.bananas-playground.net/projekt/scientia + +!WARNING! +This is a very simple, with limited experience written, go program. +Use at own risk and feel free to improve. + +Howto build: +Nothing special, just go build -o scientia-tui diff --git a/client/go-tui/TODO b/client/go-tui/TODO new file mode 100644 index 0000000..e9f8f34 --- /dev/null +++ b/client/go-tui/TODO @@ -0,0 +1 @@ +Reset the create input field. Not sure where yet. diff --git a/client/go-tui/create.go b/client/go-tui/create.go new file mode 100644 index 0000000..ae5c8c9 --- /dev/null +++ b/client/go-tui/create.go @@ -0,0 +1,85 @@ +/** + * scientia + * + * A terminal client written in go. + * + * Copyright 2023 Johannes Keßler + * + * https://www.bananas-playground.net/projekt/scientia/ + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the COMMON DEVELOPMENT AND DISTRIBUTION LICENSE + * + * You should have received a copy of the + * COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + * along with this program. If not, see http://www.sun.com/cddl/cddl.html + * + * + * This is the create "screen". It displays a textarea to input text into. + * Does the save and creation + */ +package main + +import ( + "github.com/charmbracelet/bubbles/textarea" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" +) + +var ( + headline = lipgloss.NewStyle().Margin(1, 0, 1, 2) + infoText = lipgloss.NewStyle().Margin(1, 0, 1, 2).Foreground(lipgloss.AdaptiveColor{Light: "#969B86", Dark: "#696969"}) +) + +func initCreate() textarea.Model { + ta := textarea.New() + ta.Placeholder = "Once upon a time..." + ta.SetHeight(10) + ta.SetWidth(50) + ta.Focus() + + return ta +} + +func createView(m mainModel) string { + return lipgloss.JoinVertical(lipgloss.Left, + headline.Render("Create a new entry"), m.create.View(), + infoText.Render("esc*2 to get back and discard. ctrl+s to save.")) +} + +func createUpdate(msg tea.Msg, m mainModel) (tea.Model, tea.Cmd) { + + var cmds []tea.Cmd + var cmd tea.Cmd + + switch msg := msg.(type) { + + case tea.KeyMsg: + switch msg.Type { + case tea.KeyCtrlC: + m.quitting = true + return m, tea.Quit + case tea.KeyCtrlS: + m.choice = "" + return m, nil + + case tea.KeyEsc: + if m.create.Focused() { + m.create.Blur() + } else if !m.create.Focused() { + m.choice = "" + return m, nil + } + default: + if !m.create.Focused() { + cmd = m.create.Focus() + cmds = append(cmds, cmd) + } + } + } + + m.create, cmd = m.create.Update(msg) + cmds = append(cmds, cmd) + return m, tea.Batch(cmds...) +} diff --git a/client/go-tui/go.mod b/client/go-tui/go.mod new file mode 100644 index 0000000..479490f --- /dev/null +++ b/client/go-tui/go.mod @@ -0,0 +1,28 @@ +module scientia/go-client + +go 1.19 + +require ( + github.com/charmbracelet/bubbles v0.14.0 + github.com/charmbracelet/bubbletea v0.23.1 + github.com/charmbracelet/lipgloss v0.6.0 +) + +require ( + github.com/atotto/clipboard v0.1.4 // indirect + github.com/aymanbagabas/go-osc52 v1.2.1 // indirect + github.com/containerd/console v1.0.3 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mattn/go-localereader v0.0.1 // indirect + github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/muesli/ansi v0.0.0-20221106050444-61f0cd9a192a // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/muesli/reflow v0.3.0 // indirect + github.com/muesli/termenv v0.13.0 // indirect + github.com/rivo/uniseg v0.4.3 // indirect + github.com/sahilm/fuzzy v0.1.0 // indirect + golang.org/x/sys v0.4.0 // indirect + golang.org/x/term v0.4.0 // indirect + golang.org/x/text v0.6.0 // indirect +) diff --git a/client/go-tui/go.sum b/client/go-tui/go.sum new file mode 100644 index 0000000..eb1c470 --- /dev/null +++ b/client/go-tui/go.sum @@ -0,0 +1,72 @@ +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= +github.com/aymanbagabas/go-osc52 v1.0.3 h1:DTwqENW7X9arYimJrPeGZcV0ln14sGMt3pHZspWD+Mg= +github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4= +github.com/aymanbagabas/go-osc52 v1.2.1 h1:q2sWUyDcozPLcLabEMd+a+7Ea2DitxZVN9hTxab9L4E= +github.com/aymanbagabas/go-osc52 v1.2.1/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4= +github.com/charmbracelet/bubbles v0.14.0 h1:DJfCwnARfWjZLvMglhSQzo76UZ2gucuHPy9jLWX45Og= +github.com/charmbracelet/bubbles v0.14.0/go.mod h1:bbeTiXwPww4M031aGi8UK2HT9RDWoiNibae+1yCMtcc= +github.com/charmbracelet/bubbletea v0.21.0/go.mod h1:GgmJMec61d08zXsOhqRC/AiOx4K4pmz+VIcRIm1FKr4= +github.com/charmbracelet/bubbletea v0.23.1 h1:CYdteX1wCiCzKNUlwm25ZHBIc1GXlYFyUIte8WPvhck= +github.com/charmbracelet/bubbletea v0.23.1/go.mod h1:JAfGK/3/pPKHTnAS8JIE2u9f61BjWTQY57RbT25aMXU= +github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= +github.com/charmbracelet/lipgloss v0.5.0/go.mod h1:EZLha/HbzEt7cYqdFPovlqy5FZPj0xFhg5SaqxScmgs= +github.com/charmbracelet/lipgloss v0.6.0 h1:1StyZB9vBSOyuZxQUcUwGr17JmojPNm87inij9N3wJY= +github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk= +github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= +github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34= +github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= +github.com/muesli/ansi v0.0.0-20221106050444-61f0cd9a192a h1:jlDOeO5TU0pYlbc/y6PFguab5IjANI0Knrpg3u/ton4= +github.com/muesli/ansi v0.0.0-20221106050444-61f0cd9a192a/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= +github.com/muesli/cancelreader v0.2.0/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ= +github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= +github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= +github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs= +github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs= +github.com/muesli/termenv v0.13.0 h1:wK20DRpJdDX8b7Ek2QfhvqhRQFZ237RGRO0RQ/Iqdy0= +github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= +github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI= +github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/client/go-tui/scientia-tui.go b/client/go-tui/scientia-tui.go new file mode 100644 index 0000000..8864044 --- /dev/null +++ b/client/go-tui/scientia-tui.go @@ -0,0 +1,94 @@ +/** + * scientia + * + * A terminal client written in go. + * + * Copyright 2023 Johannes Keßler + * + * https://www.bananas-playground.net/projekt/scientia/ + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the COMMON DEVELOPMENT AND DISTRIBUTION LICENSE + * + * You should have received a copy of the + * COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + * along with this program. If not, see http://www.sun.com/cddl/cddl.html + */ +package main + +import ( + "fmt" + "github.com/charmbracelet/bubbles/textarea" + "github.com/charmbracelet/lipgloss" + "os" + + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" +) + +// the unique identifiers for each action of the initial list of actions +const ( + ITEM_CREATE_VALUE = "create" + ITEM_LIST_VALUE = "list" + ITEM_UPDATE_VALUE = "update" +) + +// some global vars +var ( + quitTextStyle = lipgloss.NewStyle().Margin(1, 0, 1, 2) +) + +// mainModel Holds all the important stuff +// Needs to be extended if a new action is added +type mainModel struct { + start list.Model + create textarea.Model + choice string + quitting bool +} + +func (m mainModel) Init() tea.Cmd { + return nil +} + +// Update The main Update method. Decides the correct action update method +func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch m.choice { + case ITEM_UPDATE_VALUE: + //return quitTextStyle.Render("Update it is") + case ITEM_LIST_VALUE: + //return quitTextStyle.Render("List it is") + case ITEM_CREATE_VALUE: + return createUpdate(msg, m) + } + return startUpdate(msg, m) +} + +// View The main View method. Decides which action view is called +func (m mainModel) View() string { + if m.quitting { + return quitTextStyle.Render("Good day.") + } + + switch m.choice { + case ITEM_UPDATE_VALUE: + return quitTextStyle.Render("Update it is") + case ITEM_LIST_VALUE: + return quitTextStyle.Render("List it is") + case ITEM_CREATE_VALUE: + return createView(m) + } + + return startView(m) +} + +func main() { + m := mainModel{start: initStart(), create: initCreate()} + p := tea.NewProgram(m) + + if err := p.Start(); err != nil { + fmt.Println("Error running program:", err) + os.Exit(1) + } +} diff --git a/client/go-tui/start.go b/client/go-tui/start.go new file mode 100644 index 0000000..043c219 --- /dev/null +++ b/client/go-tui/start.go @@ -0,0 +1,134 @@ +/** + * scientia + * + * A terminal client written in go. + * + * Copyright 2023 Johannes Keßler + * + * https://www.bananas-playground.net/projekt/scientia/ + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the COMMON DEVELOPMENT AND DISTRIBUTION LICENSE + * + * You should have received a copy of the + * COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + * along with this program. If not, see http://www.sun.com/cddl/cddl.html + * + * + * This is the start "screen" which displays the available actions which can be selected. + * The values and identifiers are defined in the main file, since they are used there too + */ +package main + +import ( + "fmt" + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "io" +) + +var ( + titleStyle = lipgloss.NewStyle().MarginLeft(0) + itemStyle = lipgloss.NewStyle().PaddingLeft(4) + selectedItemStyle = lipgloss.NewStyle().PaddingLeft(2).Foreground(lipgloss.Color("170")) + paginationStyle = list.DefaultStyles().PaginationStyle.PaddingLeft(4) + helpStyle = list.DefaultStyles().HelpStyle.PaddingLeft(4).PaddingBottom(1) +) + + +// item stuff +type item struct { + title, desc string +} +func (i item) Title() string { return i.title } +func (i item) Description() string { return i.desc } +func (i item) FilterValue() string { return i.title } + +type itemDelegate struct{} + +func (d itemDelegate) Height() int { + return 1 +} +func (d itemDelegate) Spacing() int { + return 0 +} +func (d itemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { + return nil +} +func (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) { + i, ok := listItem.(item) + if !ok { + return + } + + str := fmt.Sprintf("%d. %s", index+1, i.Title()) + + fn := itemStyle.Render + if index == m.Index() { + fn = func(s string) string { + return selectedItemStyle.Render("> " + s) + } + } + + fmt.Fprint(w, fn(str)) +} + +func initStart() list.Model { + items := []list.Item { + item{title: "Create", desc: ITEM_CREATE_VALUE}, + item{title: "List", desc: ITEM_LIST_VALUE}, + item{title: "Update", desc: ITEM_UPDATE_VALUE}, + } + + l := list.New(items, itemDelegate{}, 20, 14) + l.Title = "Please select an option" + l.SetShowStatusBar(false) + l.SetFilteringEnabled(false) + l.Styles.Title = titleStyle + l.Styles.PaginationStyle = paginationStyle + l.Styles.HelpStyle = helpStyle + + return l +} + +func startView(m mainModel) string { + return fmt.Sprintf("\n%s", m.start.View()) +} + +func startUpdate(msg tea.Msg, m mainModel) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.WindowSizeMsg: + m.start.SetWidth(msg.Width) + return m, nil + + case tea.KeyMsg: + switch msg.Type { + // esc does close? + case tea.KeyEsc: + return m, nil + case tea.KeyCtrlC: + m.quitting = true + return m, tea.Quit + + case tea.KeyEnter: + i, ok := m.start.SelectedItem().(item) + if ok { + m.choice = i.Description() + } + return m, nil + + case tea.KeyRunes: + switch string(msg.Runes) { + case "q": + m.quitting = true + return m, tea.Quit + } + } + } + + var cmd tea.Cmd + m.start, cmd = m.start.Update(msg) + return m, cmd +}