Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve command line argument handling #87

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 141 additions & 48 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,71 +3,164 @@ package main
import (
"fmt"
"os"
"strings"
"regexp"
"unicode"

"github.com/NuruProgramming/Nuru/repl"
"github.com/NuruProgramming/Nuru/styles"
"github.com/charmbracelet/lipgloss"
)

var (
Title = styles.TitleStyle.
Render(`
█░░ █░█ █▀▀ █░█ ▄▀█   █▄█ ▄▀█   █▄░█ █░█ █▀█ █░█
█▄▄ █▄█ █▄█ █▀█ █▀█   ░█░ █▀█   █░▀█ █▄█ █▀▄ █▄█`)
Version = styles.VersionStyle.Render("v0.5.1")
Author = styles.AuthorStyle.Render("by Avicenna")
NewLogo = lipgloss.JoinVertical(lipgloss.Center, Title, lipgloss.JoinHorizontal(lipgloss.Center, Author, " | ", Version))
Help = styles.HelpStyle.Italic(false).Render(fmt.Sprintf(`💡 Namna ya kutumia Nuru:
%s: Kuanza programu ya Nuru
%s: Kuendesha faili la Nuru
%s: Kusoma nyaraka za Nuru
%s: Kufahamu toleo la Nuru
`,
styles.HelpStyle.Bold(true).Render("nuru"),
styles.HelpStyle.Bold(true).Render("nuru jinaLaFile.nr"),
styles.HelpStyle.Bold(true).Render("nuru --nyaraka"),
styles.HelpStyle.Bold(true).Render("nuru --toleo")))
)
type flagsPassed struct {
help bool
version bool
msaada bool
}

type passedArgs struct {
flags flagsPassed
args []string
}

var nuruVersion = "v0.5.1"

func main() {
pa, err := parseArgs(os.Args[1:])
if err != nil {
fmt.Fprintf(os.Stderr, "%s\n\n", err)
msaada(1)
}

args := os.Args
if len(args) < 2 {
flags := pa.flags
handleFlags(flags)

help := styles.HelpStyle.Render("💡 Tumia exit() au toka() kuondoka")
fmt.Println(lipgloss.JoinVertical(lipgloss.Left, NewLogo, "\n", help))
args := pa.args
if len(args) <= 0 {
pre_text := fmt.Sprintf(`nuru version %s
tumia toka() ama exit() kundoka.
`, nuruVersion)
fmt.Println(pre_text)
repl.Start()
return
}

if len(args) == 2 {
switch args[1] {
case "msaada", "-msaada", "--msaada", "help", "-help", "--help", "-h":
fmt.Println(Help)
case "version", "-version", "--version", "-v", "v", "--toleo", "-toleo":
fmt.Println(NewLogo)
case "-docs", "--docs", "-nyaraka", "--nyaraka":
repl.Docs()
default:
file := args[1]
content, err := os.ReadFile(args[0])
if err != nil {
fmt.Fprintf(os.Stderr, "Nuru imeshindwa kusoma faili %s\n", args[0])
os.Exit(1)
}
repl.Read(string(content))

if strings.HasSuffix(file, "nr") || strings.HasSuffix(file, ".sw") {
contents, err := os.ReadFile(file)
if err != nil {
fmt.Println(styles.ErrorStyle.Render("Error: Nuru imeshindwa kusoma faili: ", args[1]))
os.Exit(1)
}

// call the relevant functions or do the neccesary action
func handleFlags(flags flagsPassed) {
if flags.help {
help()
}
if flags.version {
version()
}
if flags.msaada {
msaada()
}
}

// parse the arguments passed in from stdin (or where they are received from)
// It follows closely with the GNU Argument Syntax:
// https://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
// Arguments and flags are each populated differently.
// If any argument is found that is not defined, then parsing stops and an error returned.
func parseArgs(args []string) (passedArgs, error) {
var pa passedArgs
for _, arg := range args {
var multiple = regexp.MustCompile(`^-[\w]{2,}$`)
if multiple.MatchString(arg) {
for _, ml := range arg[1:] {
if unicode.IsSpace(ml) {
continue
}
switch ml {
case 'h':
pa.flags.help = true
case 'm':
pa.flags.msaada = true
case 'v':
pa.flags.version = true
default:
return pa, fmt.Errorf("-%s haijafanuliwa kama bendera lakini imepatikana", string(ml))
}
}

repl.Read(string(contents))
} else {
fmt.Println(styles.ErrorStyle.Render("'"+file+"'", "sii faili sahihi. Tumia faili la '.nr' au '.sw'"))
os.Exit(1)
continue
}
switch arg {
case "--help", "-h":
pa.flags.help = true
case "--msaada", "-m":
pa.flags.msaada = true
case "--version", "-v", "--toleo", "-t":
pa.flags.version = true
default:
var re = regexp.MustCompile(`^--?`)
if re.MatchString(arg) {
return pa, fmt.Errorf("%s haijafanuliwa kama bendera lakini imepatikana", arg)
}
pa.args = append(pa.args, arg)
}
}

return pa, nil
}

func printHelpMessage(exitCode int, message string) {
issue := "If there is an error please file a bug at: https://github.com/NuruProgramming/Nuru/issues"
message = fmt.Sprintf("%s\n%s\n", message, issue)
if exitCode != 0 {
fmt.Fprintf(os.Stderr, message)
} else {
fmt.Println(styles.ErrorStyle.Render("Error: Operesheni imeshindikana boss."))
fmt.Println(Help)
os.Exit(1)
fmt.Fprintf(os.Stdout, message)
}
os.Exit(exitCode)
}

func help(args ...int) {
exitCode := 0
if len(args) > 0 {
exitCode = args[0]
}
str := `nuru programming language

usage: nuru [option] [file]

Flags:
--help: Display this help message
--version: Display the current version
`
printHelpMessage(exitCode, str)
}

func msaada(args ...int) {
exitCode := 0
if len(args) > 0 {
exitCode = args[0]
}
ms := `Lugha ya programu ya Nuru

Matumizi: nuru [chaguo] [faili]

Bendera:
--msaada: Onyesha ujumbe huu wa msaada
--toleo: Onyesha toleo la sasa
`
printHelpMessage(exitCode, ms)
}

func version() {
ver := fmt.Sprintf(`nuru programming %s
Copyright (C) 2024 Nuru Authors.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANDABILITY or FITNESS FOR A PARTICULAR PURPOSE.
`, nuruVersion)

fmt.Println(ver)
os.Exit(0)
}