From 57c782546739fde08138b00e2d0b3ba5f18fb676 Mon Sep 17 00:00:00 2001 From: "Gabriel A. Giovanini" Date: Fri, 19 Apr 2024 18:22:50 +0200 Subject: ref: Better organize the files --- .gitignore | 4 + Makefile | 10 ++- app.go | 160 ------------------------------------- cmd/dict/main.go | 27 +++++++ cmd/importer/importer.go | 131 ++++++++++++++++++++++++++++++ cmd/ui/ui.go | 105 +++++++++++++++++++++++++ db.go | 201 ----------------------------------------------- db/db.go | 198 ++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 6 +- go.sum | 8 ++ main.go | 25 ------ 11 files changed, 485 insertions(+), 390 deletions(-) delete mode 100644 app.go create mode 100644 cmd/dict/main.go create mode 100644 cmd/importer/importer.go create mode 100644 cmd/ui/ui.go delete mode 100644 db.go create mode 100644 db/db.go delete mode 100644 main.go diff --git a/.gitignore b/.gitignore index e660fd9..50e293e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ bin/ +ext/*.so + +dict.txt +main.dict diff --git a/Makefile b/Makefile index 1fa3b49..eb08518 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,17 @@ BIN?=bin/dict +GO_BUILD=go build -v --tags "fts5" +GO_RUN=go run -v --tags "fts5" + buid: ext - go build -v --tags "fts5" -o $(BIN) . + $(GO_BUILD) -o $(BIN) ./cmd/dict/main.go run: ext - go run -v --tags "fts5" . + $(GO_RUN) ./cmd/dict/main.go + import: ext - go run -v --tags "fts5" . import + $(GO_RUN) ./cmd/dict/main.go import ext: gcc -shared -o ext/libsqlite3ext.so -fPIC ext/spellfix.c diff --git a/app.go b/app.go deleted file mode 100644 index b35c049..0000000 --- a/app.go +++ /dev/null @@ -1,160 +0,0 @@ -package main - -import ( - "bufio" - "bytes" - "context" - "fmt" - "io" - "log/slog" - "math" - "os" - "strings" - - "github.com/rivo/tview" -) - -const ( - memory = ":memory:" -) - -func run(ctx context.Context, name string) error { - db, err := Open(memory) - if err != nil { - return err - } - - err = db.Restore(ctx, name) - if err != nil { - return err - } - - list := tview.NewList() - - input := tview.NewInputField(). - SetLabel("S:"). - SetChangedFunc(func(v string) { - list.Clear() - - words, err := db.SelectDict(ctx, v, 100) - if err != nil { - return - } - - for _, w := range words { - list.AddItem(w.Word, w.Line, 0, nil) - } - }). - SetAutocompleteFunc(func(v string) []string { - if len(v) == 0 { - return []string{} - } - - vs, err := db.SelectSpell(ctx, v) - if err != nil { - slog.Error("Error select spelling", "error", err) - return []string{} - } - - return vs - }) - - grid := tview.NewGrid(). - SetRows(1, 0, 3). - AddItem(input, 0, 0, 1, 3, 0, 0, false). - AddItem(list, 1, 0, 1, 3, 0, 0, false) - - err = tview.NewApplication(). - SetRoot(grid, true). - SetFocus(input). - Run() - - return err -} - -func importDict(ctx context.Context, name string) error { - db, err := Open(memory) - if err != nil { - return err - } - err = db.Migrate(ctx) - if err != nil { - return err - } - - file, err := os.Open("dict.txt") - if err != nil { - return err - } - defer file.Close() - - count := 0 - total, err := LineCounter(file) - if err != nil { - return err - } - - _, err = file.Seek(0, 0) - if err != nil { - return err - } - - scanner := bufio.NewScanner(file) - for scanner.Scan() { - if strings.HasPrefix(scanner.Text(), "#") || scanner.Text() == "" { - continue - } - - if err := db.InsertLine(ctx, scanner.Text()); err != nil { - return err - } - count++ - - if (count % 1234) == 0 { - fmt.Print("\033[G\033[K") // move the cursor left and clear the line - per := math.Ceil((float64(count) / float64(total)) * 100.0) - fmt.Printf("%d/%d (%.0f%%)", count, total, per) - } - } - - fmt.Printf("Consolidating") - err = db.Consolidade(ctx) - if err != nil { - return err - } - - err = db.Backup(ctx, name) - if err != nil { - return err - } - return nil -} - -func LineCounter(r io.Reader) (int, error) { - var count int - const lineBreak = '\n' - - buf := make([]byte, bufio.MaxScanTokenSize) - - for { - bufferSize, err := r.Read(buf) - if err != nil && err != io.EOF { - return 0, err - } - - var buffPosition int - for { - i := bytes.IndexByte(buf[buffPosition:], lineBreak) - if i == -1 || bufferSize == buffPosition { - break - } - buffPosition += i + 1 - count++ - } - if err == io.EOF { - break - } - } - - return count, nil -} diff --git a/cmd/dict/main.go b/cmd/dict/main.go new file mode 100644 index 0000000..09e9412 --- /dev/null +++ b/cmd/dict/main.go @@ -0,0 +1,27 @@ +package main + +import ( + "log/slog" + "os" + + "github.com/urfave/cli/v2" + + "git.gabrielgio.me/dict/cmd/importer" + "git.gabrielgio.me/dict/cmd/ui" +) + +func main() { + app := &cli.App{ + Name: "dict", + Usage: "interactive dictionary", + Commands: []*cli.Command{ + importer.ImportCommand, + ui.UICommand, + }, + } + + if err := app.Run(os.Args); err != nil { + slog.Error("Error running application", "error", err) + os.Exit(1) + } +} diff --git a/cmd/importer/importer.go b/cmd/importer/importer.go new file mode 100644 index 0000000..18a7a7b --- /dev/null +++ b/cmd/importer/importer.go @@ -0,0 +1,131 @@ +package importer + +import ( + "bufio" + "bytes" + "context" + "fmt" + "io" + "math" + "os" + "strings" + + "github.com/urfave/cli/v2" + + "git.gabrielgio.me/dict/db" +) + +var ImportCommand = &cli.Command{ + Name: "import", + Usage: "convert dict.cc dictionary into a queryable sqlite format.", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "output", + Value: "main.dict", + Usage: "Dictionary database location", + }, + &cli.StringFlag{ + Name: "input", + Value: "dict.txt", + Usage: "Dict.cc txt dictionary file", + }, + }, + Action: func(cCtx *cli.Context) error { + input := cCtx.String("input") + output := cCtx.String("output") + return Import(context.Background(), input, output) + }, +} + +func Import(ctx context.Context, txtInput, sqliteOutput string) error { + db, err := db.Open(":memory:") + if err != nil { + return err + } + err = db.Migrate(ctx) + if err != nil { + return err + } + + file, err := os.Open(txtInput) + if err != nil { + return err + } + defer file.Close() + + count := 0 + total, err := lineCounter(file) + if err != nil { + return err + } + + _, err = file.Seek(0, 0) + if err != nil { + return err + } + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + if strings.HasPrefix(scanner.Text(), "#") || scanner.Text() == "" { + continue + } + + var ( + p = strings.SplitN(scanner.Text(), "\t", 2) + word = p[0] + line = strings.ReplaceAll(p[1], "\t", " ") + ) + + if err := db.InsertLine(ctx, word, line); err != nil { + return err + } + count++ + + if (count % 1234) == 0 { + fmt.Print("\033[G\033[K") // move the cursor left and clear the line + per := math.Ceil((float64(count) / float64(total)) * 100.0) + fmt.Printf("%d/%d (%.0f%%)", count, total, per) + } + } + + fmt.Printf("Consolidating") + err = db.Consolidade(ctx) + if err != nil { + return err + } + + err = db.Backup(ctx, sqliteOutput) + if err != nil { + return err + } + return nil +} + +func lineCounter(r io.Reader) (int, error) { + var count int + const lineBreak = '\n' + + buf := make([]byte, bufio.MaxScanTokenSize) + + for { + bufferSize, err := r.Read(buf) + if err != nil && err != io.EOF { + return 0, err + } + + var buffPosition int + for { + i := bytes.IndexByte(buf[buffPosition:], lineBreak) + if i == -1 || bufferSize == buffPosition { + break + } + buffPosition += i + 1 + count++ + } + if err == io.EOF { + break + } + } + + return count, nil +} diff --git a/cmd/ui/ui.go b/cmd/ui/ui.go new file mode 100644 index 0000000..82c0bc5 --- /dev/null +++ b/cmd/ui/ui.go @@ -0,0 +1,105 @@ +package ui + +import ( + "context" + "fmt" + "log/slog" + + "github.com/gdamore/tcell/v2" + "github.com/rivo/tview" + "github.com/urfave/cli/v2" + + "git.gabrielgio.me/dict/db" +) + +const ( + memory = ":memory:" +) + +var UICommand = &cli.Command{ + Name: "ui", + Usage: "interactive dictionary", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "filename", + Value: "main.dict", + Usage: "Dictionary database location", + }, + }, + Action: func(cCtx *cli.Context) error { + name := cCtx.String("lang") + return Run(context.Background(), name) + }, +} + +func Run(ctx context.Context, name string) error { + db, err := db.Open(memory) + if err != nil { + return err + } + + err = db.Restore(ctx, name) + if err != nil { + return err + } + + textView := tview.NewTextView(). + SetDynamicColors(true). + SetRegions(true) + + input := tview.NewInputField(). + SetChangedFunc(func(v string) { + textView.Clear() + + words, err := db.SelectDict(ctx, v, 100) + if err != nil { + return + } + + lastWord := "" + for _, w := range words { + + if lastWord == w.Word { + fmt.Fprintf(textView, "%s\n", w.Line) + } else if lastWord == "" { + fmt.Fprintf(textView, "[bold]%s[normal]\n", w.Word) + fmt.Fprintf(textView, "%s\n", w.Line) + } else { + fmt.Fprintf(textView, "\n[bold]%s[normal]\n", w.Word) + fmt.Fprintf(textView, "%s\n", w.Line) + } + + lastWord = w.Word + } + }). + SetAutocompleteFunc(func(v string) []string { + if len(v) == 0 { + return []string{} + } + + vs, err := db.SelectSpell(ctx, v) + if err != nil { + slog.Error("Error select spelling", "error", err) + return []string{} + } + + return vs + }) + + input.SetDoneFunc(func(key tcell.Key) { + textView.Clear() + input.SetText("") + }) + + grid := tview.NewGrid(). + SetRows(1, 0, 3). + AddItem(input, 0, 0, 1, 3, 0, 0, false). + AddItem(textView, 1, 0, 1, 3, 0, 0, false) + + err = tview.NewApplication(). + SetRoot(grid, true). + SetFocus(input). + Run() + + return err +} diff --git a/db.go b/db.go deleted file mode 100644 index b105414..0000000 --- a/db.go +++ /dev/null @@ -1,201 +0,0 @@ -package main - -import ( - "context" - "database/sql" - "fmt" - "strings" - - "github.com/mattn/go-sqlite3" -) - -type ( - DB struct { - db *sql.DB - source string // for backup - } - - Word struct { - Word string - Line string - } -) - -func Open(filename string) (*DB, error) { - sql.Register("sqlite3_with_extensions", &sqlite3.SQLiteDriver{ - ConnectHook: func(conn *sqlite3.SQLiteConn) error { - return conn.LoadExtension("ext/libsqlite3ext", "sqlite3_spellfix_init") - }, - }) - - db, err := sql.Open("sqlite3_with_extensions", filename) - if err != nil { - return nil, err - } - - return &DB{ - db: db, - source: filename, - }, nil -} - -func (d *DB) Migrate(ctx context.Context) error { - _, err := d.db.ExecContext( - ctx, - `CREATE VIRTUAL TABLE IF NOT EXISTS words USING fts5 (word, line); - CREATE VIRTUAL TABLE IF NOT EXISTS words_terms USING fts4aux(words); - CREATE VIRTUAL TABLE IF NOT EXISTS spell USING spellfix1; - `, - ) - return err -} - -func (d *DB) SelectDict(ctx context.Context, query string, limit int) ([]*Word, error) { - rows, err := d.db.QueryContext( - ctx, - `SELECT - word, line - FROM words - WHERE word MATCH ? - ORDER BY rank;`, - query, limit, - ) - if err != nil { - return nil, err - } - - words := make([]*Word, 0) - for rows.Next() { - w := Word{} - err := rows.Scan(&w.Word, &w.Line) - if err != nil { - return nil, err - } - words = append(words, &w) - } - - return words, err - -} - -func (d *DB) SelectSpell(ctx context.Context, query string) ([]string, error) { - rows, err := d.db.QueryContext( - ctx, - `SELECT - word - FROM spell - WHERE word MATCH ?;`, - query, - ) - if err != nil { - return nil, err - } - - words := make([]string, 0) - for rows.Next() { - w := "" - err := rows.Scan(&w) - if err != nil { - return nil, err - } - words = append(words, w) - } - - return words, err - -} - -func (d *DB) InsertLine(ctx context.Context, line string) error { - p := strings.SplitN(line, "\t", 2) - - _, err := d.db.ExecContext( - ctx, - `INSERT INTO words (WORD, LINE) VALUES(?, ?);`, - p[0], strings.ReplaceAll(p[1], "\t", " "), - ) - if err != nil { - return err - } - return err -} - -func (d *DB) Consolidade(ctx context.Context) error { - _, err := d.db.ExecContext( - ctx, - `INSERT INTO spell(word,rank) - SELECT term, documents FROM words_terms WHERE col='*'`, - ) - if err != nil { - return err - } - return err -} - -func (d *DB) Backup(ctx context.Context, name string) error { - destDb, err := sql.Open("sqlite3_with_extensions", name) - if err != nil { - return err - } - defer destDb.Close() - - return Copy(ctx, d.db, destDb) -} - -func (d *DB) Restore(ctx context.Context, name string) error { - srcDb, err := sql.Open("sqlite3_with_extensions", name) - if err != nil { - return err - } - defer srcDb.Close() - - return Copy(ctx, srcDb, d.db) -} - -func Copy(ctx context.Context, srcDb *sql.DB, destDb *sql.DB) error { - destConn, err := destDb.Conn(ctx) - if err != nil { - return err - } - defer destConn.Close() - - srcConn, err := srcDb.Conn(ctx) - if err != nil { - return err - } - defer srcConn.Close() - - return destConn.Raw(func(destConn interface{}) error { - return srcConn.Raw(func(srcConn interface{}) error { - destSQLiteConn, ok := destConn.(*sqlite3.SQLiteConn) - if !ok { - return fmt.Errorf("can't convert destination connection to SQLiteConn") - } - - srcSQLiteConn, ok := srcConn.(*sqlite3.SQLiteConn) - if !ok { - return fmt.Errorf("can't convert source connection to SQLiteConn") - } - - b, err := destSQLiteConn.Backup("main", srcSQLiteConn, "main") - if err != nil { - return fmt.Errorf("error initializing SQLite backup: %w", err) - } - - done, err := b.Step(-1) - if !done { - return fmt.Errorf("step of -1, but not done") - } - if err != nil { - return fmt.Errorf("error in stepping backup: %w", err) - } - - err = b.Finish() - if err != nil { - return fmt.Errorf("error finishing backup: %w", err) - } - - return err - }) - }) - -} diff --git a/db/db.go b/db/db.go new file mode 100644 index 0000000..746c30d --- /dev/null +++ b/db/db.go @@ -0,0 +1,198 @@ +package db + +import ( + "context" + "database/sql" + "fmt" + + "github.com/mattn/go-sqlite3" +) + +type ( + DB struct { + db *sql.DB + source string // for backup + } + + Word struct { + Word string + Line string + } +) + +func Open(filename string) (*DB, error) { + sql.Register("sqlite3_with_extensions", &sqlite3.SQLiteDriver{ + ConnectHook: func(conn *sqlite3.SQLiteConn) error { + return conn.LoadExtension("ext/libsqlite3ext", "sqlite3_spellfix_init") + }, + }) + + db, err := sql.Open("sqlite3_with_extensions", filename) + if err != nil { + return nil, err + } + + return &DB{ + db: db, + source: filename, + }, nil +} + +func (d *DB) Migrate(ctx context.Context) error { + _, err := d.db.ExecContext( + ctx, + `CREATE VIRTUAL TABLE IF NOT EXISTS words USING fts5 (word, line); + CREATE VIRTUAL TABLE IF NOT EXISTS words_terms USING fts4aux(words); + CREATE VIRTUAL TABLE IF NOT EXISTS spell USING spellfix1; + `, + ) + return err +} + +func (d *DB) SelectDict(ctx context.Context, query string, limit int) ([]*Word, error) { + rows, err := d.db.QueryContext( + ctx, + `SELECT + word, line + FROM words + WHERE word MATCH ? + ORDER BY rank;`, + query, limit, + ) + if err != nil { + return nil, err + } + + words := make([]*Word, 0) + for rows.Next() { + w := Word{} + err := rows.Scan(&w.Word, &w.Line) + if err != nil { + return nil, err + } + words = append(words, &w) + } + + return words, err + +} + +func (d *DB) SelectSpell(ctx context.Context, query string) ([]string, error) { + rows, err := d.db.QueryContext( + ctx, + `SELECT + word + FROM spell + WHERE word MATCH ?;`, + query, + ) + if err != nil { + return nil, err + } + + words := make([]string, 0) + for rows.Next() { + w := "" + err := rows.Scan(&w) + if err != nil { + return nil, err + } + words = append(words, w) + } + + return words, err + +} + +func (d *DB) InsertLine(ctx context.Context, word, line string) error { + _, err := d.db.ExecContext( + ctx, + `INSERT INTO words (WORD, LINE) VALUES(?, ?);`, + word, line, + ) + if err != nil { + return err + } + return err +} + +func (d *DB) Consolidade(ctx context.Context) error { + _, err := d.db.ExecContext( + ctx, + `INSERT INTO spell(word,rank) + SELECT term, documents FROM words_terms WHERE col='*'`, + ) + if err != nil { + return err + } + return err +} + +func (d *DB) Backup(ctx context.Context, name string) error { + destDb, err := sql.Open("sqlite3_with_extensions", name) + if err != nil { + return err + } + defer destDb.Close() + + return Copy(ctx, d.db, destDb) +} + +func (d *DB) Restore(ctx context.Context, name string) error { + srcDb, err := sql.Open("sqlite3_with_extensions", name) + if err != nil { + return err + } + defer srcDb.Close() + + return Copy(ctx, srcDb, d.db) +} + +func Copy(ctx context.Context, srcDb *sql.DB, destDb *sql.DB) error { + destConn, err := destDb.Conn(ctx) + if err != nil { + return err + } + defer destConn.Close() + + srcConn, err := srcDb.Conn(ctx) + if err != nil { + return err + } + defer srcConn.Close() + + return destConn.Raw(func(destConn interface{}) error { + return srcConn.Raw(func(srcConn interface{}) error { + destSQLiteConn, ok := destConn.(*sqlite3.SQLiteConn) + if !ok { + return fmt.Errorf("can't convert destination connection to SQLiteConn") + } + + srcSQLiteConn, ok := srcConn.(*sqlite3.SQLiteConn) + if !ok { + return fmt.Errorf("can't convert source connection to SQLiteConn") + } + + b, err := destSQLiteConn.Backup("main", srcSQLiteConn, "main") + if err != nil { + return fmt.Errorf("error initializing SQLite backup: %w", err) + } + + done, err := b.Step(-1) + if !done { + return fmt.Errorf("step of -1, but not done") + } + if err != nil { + return fmt.Errorf("error in stepping backup: %w", err) + } + + err = b.Finish() + if err != nil { + return fmt.Errorf("error finishing backup: %w", err) + } + + return err + }) + }) + +} diff --git a/go.mod b/go.mod index 40fd8f1..9a4b5a4 100644 --- a/go.mod +++ b/go.mod @@ -4,15 +4,19 @@ go 1.21.9 require ( github.com/gdamore/tcell/v2 v2.7.4 + github.com/mattn/go-sqlite3 v1.14.22 github.com/rivo/tview v0.0.0-20240413115534-b0d41c484b95 + github.com/urfave/cli/v2 v2.27.1 ) require ( + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/gdamore/encoding v1.0.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect - github.com/mattn/go-sqlite3 v1.14.22 // indirect github.com/rivo/uniseg v0.4.7 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect golang.org/x/sys v0.17.0 // indirect golang.org/x/term v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect diff --git a/go.sum b/go.sum index 4d93204..ab0b469 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= github.com/gdamore/tcell/v2 v2.7.4 h1:sg6/UnTM9jGpZU+oFYAsDahfchWAFW8Xx2yFinNSAYU= @@ -14,6 +16,12 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho= +github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= diff --git a/main.go b/main.go deleted file mode 100644 index 5ba494f..0000000 --- a/main.go +++ /dev/null @@ -1,25 +0,0 @@ -package main - -import ( - "context" - "log/slog" - "os" -) - -func main() { - ctx := context.Background() - - if len(os.Args) > 1 && os.Args[1] == "import" { - err := importDict(ctx, "main.dict") - if err != nil { - slog.Error("Error importing", "error", err) - return - } - } else { - err := run(ctx, "main.dict") - if err != nil { - slog.Error("Error running", "error", err) - return - } - } -} -- cgit v1.2.3