From db12c9344c116517454d48dca4d5aa76e2a5dd24 Mon Sep 17 00:00:00 2001 From: Naru K Date: Mon, 13 Jul 2026 18:02:35 +0300 Subject: [PATCH 1/9] fix(format): writing a file to temp file instead of ovewrite --- format/format.go | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/format/format.go b/format/format.go index ea3d892..9b7559b 100755 --- a/format/format.go +++ b/format/format.go @@ -33,15 +33,26 @@ func Bytes(path string, src []byte) ([]byte, error) { // Path formats the file at path in place. Overwrites the original. func Path(path string) error { + // removing .tmp file in case of failure + + b, err := os.ReadFile(path) if err != nil { return err } + // Format the file and write it back to disk. out, err := Bytes(path, b) if err != nil { return err } - return os.WriteFile(path, out, 0o644) + + // writing to a temp file first, then renaming, to avoid data loss in case of errors + tmpPath := path + ".tmp" + err = os.WriteFile(tmpPath, out, 0o644) + if err != nil { + return err + } + return os.Rename(tmpPath, path) } // File renders a parsed ELU AST back to canonical formatted text. @@ -50,10 +61,13 @@ func File(f *ast.File) string { var b bytes.Buffer fmt.Fprintf(&b, "pack %q version %d\n", f.PackID, f.Version) fmt.Fprintf(&b, "type = %q\n", f.Type) + // Render all nodes in the file. for _, n := range f.Nodes { b.WriteByte('\n') writeNode(&b, n, 0) } + // Add a newline if the file didn't end with one. + // This is important for tools that expect a newline at the end of files. if !bytes.HasSuffix(b.Bytes(), []byte("\n")) { b.WriteByte('\n') } @@ -65,18 +79,22 @@ func writeNode(b *bytes.Buffer, n *ast.Node, indent int) { pad := strings.Repeat(" ", indent) switch n.Kind { case ast.NodeBlock: + // Blocks are rendered as key: name\n{ children }. fmt.Fprintf(b, "%s%s %q:\n", pad, n.Key, n.Name) for _, c := range n.Children { writeNode(b, c, indent+2) } case ast.NodeSection: + // Sections are rendered as key:\n{ children }. fmt.Fprintf(b, "%s%s:\n", pad, sectionKey(n.Key)) for _, c := range n.Children { writeNode(b, c, indent+2) } case ast.NodeAssign: + // Assignments are rendered as key = value\n. fmt.Fprintf(b, "%s%s = %s\n", pad, n.Key, renderValue(n.Value)) case ast.NodeListItem: + // List items are rendered as either an expression, a value, or a section. writeListItem(b, n, indent) } } @@ -132,13 +150,16 @@ func isBareKey(s string) bool { if s == "" { return false } + // Check first rune separately, since it can't be a digit or dot. for i, r := range s { if i == 0 { + // Check if the rune is a valid first rune. if !(r == '_' || (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z')) { return false } continue } + // Check if the rune is a valid identifier rune. if !(r == '_' || r == '.' || r == '-' || (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9')) { return false } From 17075cbb9747c328acf8d57875dd6854753f4237 Mon Sep 17 00:00:00 2001 From: Naru K Date: Mon, 13 Jul 2026 18:04:57 +0300 Subject: [PATCH 2/9] fix(format): deleting a .tmp file in case renaming failed --- format/format.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/format/format.go b/format/format.go index 9b7559b..66b0a9f 100755 --- a/format/format.go +++ b/format/format.go @@ -34,7 +34,10 @@ func Bytes(path string, src []byte) ([]byte, error) { // Path formats the file at path in place. Overwrites the original. func Path(path string) error { // removing .tmp file in case of failure - + err := os.Remove(path + ".tmp") + if err != nil { + return err + } b, err := os.ReadFile(path) if err != nil { From 87bd20f5b5f0b96c1bc28a5ca93239869779ea09 Mon Sep 17 00:00:00 2001 From: Naru K Date: Mon, 13 Jul 2026 18:06:57 +0300 Subject: [PATCH 3/9] fix(format): updated godoc comment for path function --- format/format.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/format/format.go b/format/format.go index 66b0a9f..43c2d88 100755 --- a/format/format.go +++ b/format/format.go @@ -31,7 +31,7 @@ func Bytes(path string, src []byte) ([]byte, error) { return []byte(out), nil } -// Path formats the file at path in place. Overwrites the original. +// Path formats the file at path in place. Overwrites the original. It creates a temp file first, then renames it to the original file. func Path(path string) error { // removing .tmp file in case of failure err := os.Remove(path + ".tmp") From c33b5f83fa36409a49a01efb9840e27e9a27cdb6 Mon Sep 17 00:00:00 2001 From: Naru K Date: Mon, 13 Jul 2026 18:17:49 +0300 Subject: [PATCH 4/9] fix(format): silently deleting tmp file instead of error handling --- format/format.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/format/format.go b/format/format.go index 43c2d88..0027164 100755 --- a/format/format.go +++ b/format/format.go @@ -33,12 +33,8 @@ func Bytes(path string, src []byte) ([]byte, error) { // Path formats the file at path in place. Overwrites the original. It creates a temp file first, then renames it to the original file. func Path(path string) error { - // removing .tmp file in case of failure - err := os.Remove(path + ".tmp") - if err != nil { - return err - } - + // silently remove the temp file if it exists + _ = os.Remove(path + ".tmp") b, err := os.ReadFile(path) if err != nil { return err From cb3450fd714a6d194eb53b8f8f1861f796eea91b Mon Sep 17 00:00:00 2001 From: Naru K Date: Mon, 13 Jul 2026 18:28:49 +0300 Subject: [PATCH 5/9] fix(format/Path): added error write to stderr, because some ai-chan didnt like silent ignoring lol --- format/format.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/format/format.go b/format/format.go index 0027164..9b3ec66 100755 --- a/format/format.go +++ b/format/format.go @@ -33,8 +33,12 @@ func Bytes(path string, src []byte) ([]byte, error) { // Path formats the file at path in place. Overwrites the original. It creates a temp file first, then renames it to the original file. func Path(path string) error { - // silently remove the temp file if it exists - _ = os.Remove(path + ".tmp") + // Remove the temp file if it exists. + err := os.Remove(path + ".tmp") + if err != nil { + // Print a warning if the temp file removal fails. + fmt.Fprintf(os.Stderr, "warning: failed to remove temp file %q: %v", path+".tmp", err) + } b, err := os.ReadFile(path) if err != nil { return err From eda2892bc3f5c0f6f5676692afdd147ef26ac5d4 Mon Sep 17 00:00:00 2001 From: Naru K Date: Mon, 13 Jul 2026 18:32:34 +0300 Subject: [PATCH 6/9] fix(format/Path): moved tmpPath higher in the function to reduce repetition and recalculating the path --- format/format.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/format/format.go b/format/format.go index 9b3ec66..c72accd 100755 --- a/format/format.go +++ b/format/format.go @@ -34,10 +34,12 @@ func Bytes(path string, src []byte) ([]byte, error) { // Path formats the file at path in place. Overwrites the original. It creates a temp file first, then renames it to the original file. func Path(path string) error { // Remove the temp file if it exists. - err := os.Remove(path + ".tmp") + tmpPath := path + ".tmp" + + err := os.Remove(tmpPath) if err != nil { // Print a warning if the temp file removal fails. - fmt.Fprintf(os.Stderr, "warning: failed to remove temp file %q: %v", path+".tmp", err) + fmt.Fprintf(os.Stderr, "warning: failed to remove temp file %q: %v", tmpPath, err) } b, err := os.ReadFile(path) if err != nil { @@ -50,7 +52,6 @@ func Path(path string) error { } // writing to a temp file first, then renaming, to avoid data loss in case of errors - tmpPath := path + ".tmp" err = os.WriteFile(tmpPath, out, 0o644) if err != nil { return err From 6d0e92bcb463ff83ebefdf1f6f56edb4d634b33e Mon Sep 17 00:00:00 2001 From: Naru K Date: Mon, 13 Jul 2026 18:59:56 +0300 Subject: [PATCH 7/9] fix(format/Path): full refactor to satisfy all AI-chan's concerns of my bad code writing --- format/format.go | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/format/format.go b/format/format.go index c72accd..a7571f2 100755 --- a/format/format.go +++ b/format/format.go @@ -6,6 +6,7 @@ import ( "bytes" "fmt" "os" + "path/filepath" "strings" "github.com/therxwold/elu/ast" @@ -33,30 +34,40 @@ func Bytes(path string, src []byte) ([]byte, error) { // Path formats the file at path in place. Overwrites the original. It creates a temp file first, then renames it to the original file. func Path(path string) error { - // Remove the temp file if it exists. - tmpPath := path + ".tmp" - - err := os.Remove(tmpPath) + success := false + // create a temp file + temp, err := os.CreateTemp(filepath.Dir(path), "elu-format-*") if err != nil { - // Print a warning if the temp file removal fails. - fmt.Fprintf(os.Stderr, "warning: failed to remove temp file %q: %v", tmpPath, err) + return err } + defer temp.Close() + // deleting the temp file in case of crash + defer func() { + if !success { + os.Remove(temp.Name()) + } + }() + // read the original file b, err := os.ReadFile(path) if err != nil { return err } - // Format the file and write it back to disk. - out, err := Bytes(path, b) + // write the formatted file + out, err := Bytes(temp.Name(), b) if err != nil { return err } - - // writing to a temp file first, then renaming, to avoid data loss in case of errors - err = os.WriteFile(tmpPath, out, 0o644) + _, err = temp.Write(out) if err != nil { return err } - return os.Rename(tmpPath, path) + // rename the temp file to the original file + err = os.Rename(temp.Name(), path); if err != nil { + return err + } + // set success to true + success = true + return nil } // File renders a parsed ELU AST back to canonical formatted text. From b3256f89ec580e781b51b124392b22354e8e2d75 Mon Sep 17 00:00:00 2001 From: Naru K Date: Mon, 13 Jul 2026 19:17:49 +0300 Subject: [PATCH 8/9] fix(format/Path): added windows error catching cuz Windows is always special --- format/format.go | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/format/format.go b/format/format.go index a7571f2..9f31a7d 100755 --- a/format/format.go +++ b/format/format.go @@ -7,6 +7,7 @@ import ( "fmt" "os" "path/filepath" + "runtime" "strings" "github.com/therxwold/elu/ast" @@ -40,7 +41,6 @@ func Path(path string) error { if err != nil { return err } - defer temp.Close() // deleting the temp file in case of crash defer func() { if !success { @@ -61,11 +61,29 @@ func Path(path string) error { if err != nil { return err } + // close the temp file before renaming it to the original file + temp.Close() // rename the temp file to the original file err = os.Rename(temp.Name(), path); if err != nil { + // Windows fallback; + // try to delete the original file and rename the temp file to it + if runtime.GOOS == "windows" { + // creating a bak file + bak := path + ".bak" + if err = os.Rename(path, bak); err != nil { + return err + } + // renaming the temp file to the original file + err = os.Rename(temp.Name(), path); if err != nil { + // restoring the bak file + os.Rename(bak, path) + return err + } + os.Remove(bak) + return nil + } return err } - // set success to true success = true return nil } From 5786517f6216d09cd013df1426bc3f11016b9a92 Mon Sep 17 00:00:00 2001 From: Naru K Date: Mon, 13 Jul 2026 19:19:31 +0300 Subject: [PATCH 9/9] fix(format/Path): gofmt -w --- format/format.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/format/format.go b/format/format.go index 9f31a7d..cd2f570 100755 --- a/format/format.go +++ b/format/format.go @@ -64,7 +64,8 @@ func Path(path string) error { // close the temp file before renaming it to the original file temp.Close() // rename the temp file to the original file - err = os.Rename(temp.Name(), path); if err != nil { + err = os.Rename(temp.Name(), path) + if err != nil { // Windows fallback; // try to delete the original file and rename the temp file to it if runtime.GOOS == "windows" { @@ -74,7 +75,8 @@ func Path(path string) error { return err } // renaming the temp file to the original file - err = os.Rename(temp.Name(), path); if err != nil { + err = os.Rename(temp.Name(), path) + if err != nil { // restoring the bak file os.Rename(bak, path) return err