Skip to content

Commit 7b57eb8

Browse files
committed
Add option to disable line numbering
relates to #1
1 parent 928e71f commit 7b57eb8

File tree

4 files changed

+69
-36
lines changed

4 files changed

+69
-36
lines changed

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2021-2022 David Vogel
3+
Copyright (c) 2021-2023 David Vogel
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ You only need to start the tool in any directory, and it will open a list of pat
88

99
When run from inside some directory, this program will:
1010

11-
1. Create a temporary file with a list of all files contained in the given directory and its sub directories
12-
2. Opens the temporary file with the default editor (For files with the file extension `.batch-rename`)
13-
3. Reads the file back, and renames/moves the files
11+
1. Create a temporary file with a list of all files contained in the given directory and its sub directories.
12+
2. Opens the temporary file with the default editor. (For files with the file extension `.batch-rename`)
13+
3. Reads the file back, and renames/moves the files.
1414

1515
## Usage
1616

@@ -21,11 +21,19 @@ There are multiple ways to use this tool:
2121
- Use `go install github.com/Dadido3/batch-rename@latest`. Afterwards you can run `batch-rename` from inside any directory.
2222
- Build it yourself from source, see below.
2323

24+
## Options
25+
26+
- `batch-rename --no-numbers` will disable line number output.
27+
This means that each line contains only the file path without a preceding number, which is easier to edit in some cases.
28+
Using this option has the downside that any line removal or insertion can mess up the mapping between old and new paths, which can mess up your filenames.
29+
2430
## Building
2531

2632
This software uses GoReleaser to automatically build and upload artifacts to GitHub.
2733
Make sure to [install GoReleaser](https://goreleaser.com/install/).
2834

2935
- To build for your current platform use `goreleaser build --single-target --clean`. Or `goreleaser build --single-target --snapshot --clean` if you have modified the repository.
3036
- To simulate the release process, use `goreleaser --skip-publish --auto-snapshot --clean`.
31-
- To build for your current platform and without GoReleaser, use `go build`. This will not include the version information.
37+
38+
To build for your current platform and without GoReleaser, use `go build`.
39+
This will not include the version information.

file-handling.go

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2022 David Vogel
1+
// Copyright (c) 2022-2023 David Vogel
22
//
33
// This software is released under the MIT License.
44
// https://opensource.org/licenses/MIT
@@ -15,17 +15,23 @@ import (
1515
)
1616

1717
// createEntriesFile creates a new file with all the fileEntries and returns its file path.
18-
func createEntriesFile(rootDir string, fileEntries []fileEntry) (filePath string, err error) {
18+
func createEntriesFile(rootDir string, fileEntries []fileEntry, numbering bool) (filePath string, err error) {
1919
// Create temporary file with paths.
2020
file, err := os.CreateTemp(".", "*.batch-rename")
2121
if err != nil {
2222
log.Fatal(err)
2323
}
2424

25-
decimalWidth := getDecimalWidth(uint(len(fileEntries)))
25+
if numbering {
26+
decimalWidth := getDecimalWidth(uint(len(fileEntries)))
2627

27-
for i, fileEntry := range fileEntries {
28-
fmt.Fprintf(file, "%0"+fmt.Sprint(decimalWidth)+"d\t%s\n", i+1, fileEntry.originalPath)
28+
for i, fileEntry := range fileEntries {
29+
fmt.Fprintf(file, "%0"+fmt.Sprint(decimalWidth)+"d\t%s\n", i+1, fileEntry.originalPath)
30+
}
31+
} else {
32+
for _, fileEntry := range fileEntries {
33+
fmt.Fprintf(file, "%s\n", fileEntry.originalPath)
34+
}
2935
}
3036

3137
if err := file.Close(); err != nil {
@@ -36,24 +42,38 @@ func createEntriesFile(rootDir string, fileEntries []fileEntry) (filePath string
3642
}
3743

3844
// readEntriesFile reads the (edited) temporary file back and modifies the fileEntries with the new file paths.
39-
func readEntriesFile(filePath string, fileEntries []fileEntry) error {
45+
func readEntriesFile(filePath string, fileEntries []fileEntry, numbering bool) error {
4046
file, err := os.Open(filePath)
4147
if err != nil {
4248
return err
4349
}
4450
defer file.Close()
4551

4652
scanner := bufio.NewScanner(file)
53+
i := 0
4754
for scanner.Scan() {
48-
substrings := strings.SplitN(scanner.Text(), "\t", 2)
49-
entry, err := strconv.ParseUint(substrings[0], 10, 64)
50-
if err != nil {
51-
return fmt.Errorf("failed to parse element number: %w", err)
52-
}
53-
if entry <= 0 || entry > uint64(len(fileEntries)) {
54-
return fmt.Errorf("element number outside of valid range: Given %v, there are %v entries", entry, len(fileEntries))
55+
if numbering {
56+
substrings := strings.SplitN(scanner.Text(), "\t", 2)
57+
entry, err := strconv.ParseUint(substrings[0], 10, 64)
58+
if err != nil {
59+
return fmt.Errorf("failed to parse element number: %w", err)
60+
}
61+
if entry <= 0 || entry > uint64(len(fileEntries)) {
62+
return fmt.Errorf("element number outside of valid range: Got %d, but there are only %d entries", entry, len(fileEntries))
63+
}
64+
fileEntries[entry-1].newPath = substrings[1]
65+
} else {
66+
if i >= len(fileEntries) {
67+
return fmt.Errorf("there are more lines than files: Got %d, but expected %d", i+1, len(fileEntries))
68+
}
69+
fileEntries[i].newPath = scanner.Text()
70+
i++
5571
}
56-
fileEntries[entry-1].newPath = substrings[1]
72+
}
73+
74+
// In case we don't do numbering, we should make sure that the number of lines didn't change.
75+
if !numbering && i != len(fileEntries) {
76+
return fmt.Errorf("the number of lines don't match the number of files: Got %d, but expected %d", i, len(fileEntries))
5777
}
5878

5979
if err := scanner.Err(); err != nil {
@@ -71,6 +91,8 @@ func moveFiles(fileEntries []fileEntry) error {
7191
return err
7292
}
7393
log.Printf("Renamed %q to %q", fileEntry.originalPath, fileEntry.newPath)
94+
// This is important, because if there is an error later on, we know which files were already moved.
95+
// So we can query the user to correct the list, and just call moveFiles again, without files getting messed up.
7496
fileEntry.originalPath = fileEntry.newPath
7597
}
7698
}

main.go

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2021-2022 David Vogel
1+
// Copyright (c) 2021-2023 David Vogel
22
//
33
// This software is released under the MIT License.
44
// https://opensource.org/licenses/MIT
@@ -7,6 +7,7 @@ package main
77

88
import (
99
"bufio"
10+
"flag"
1011
"io/fs"
1112
"log"
1213
"os"
@@ -15,10 +16,15 @@ import (
1516
"github.com/skratchdot/open-golang/open"
1617
)
1718

19+
var flagNoNumbers = flag.Bool("no-numbers", false, "If set, batch-rename will not prepend numbers to every line. If you enable this option you have to make sure that you don't add or remove lines, as otherwise it will mess up your filenames!")
20+
1821
func main() {
22+
flag.Parse()
23+
1924
log.Printf("Started batch-rename %v", Version)
2025

2126
rootDir := "."
27+
numbering := !*flagNoNumbers
2228

2329
fileEntries := []fileEntry{}
2430

@@ -51,51 +57,48 @@ func main() {
5157
return
5258
}
5359

54-
log.Printf("Got %d files to rename", len(fileEntries))
60+
log.Printf("Found %d files", len(fileEntries))
5561

5662
// Create temporary file.
57-
filePath, err := createEntriesFile(rootDir, fileEntries)
63+
filePath, err := createEntriesFile(rootDir, fileEntries, numbering)
5864
if err != nil {
59-
log.Panicf("Failed to create temporary text file: %v", err)
65+
log.Panicf("Failed to create file with filepaths: %v", err)
6066
}
6167

62-
/*if err := openWithDefault(filePath); err != nil {
63-
log.Panicf("Failed to open temporary text file: %v", err)
64-
}*/
65-
6668
if err := open.Run(filePath); err != nil {
67-
log.Panicf("Failed to open temporary text file: %v", err)
69+
log.Panicf("Failed to open file with filepaths: %v", err)
6870
}
6971

70-
log.Print("Editor opened, edit file paths and press any key to continue...")
72+
log.Printf("Opening %s in the default editor", filePath)
73+
log.Print("You can now edit the filepaths and press any key to continue...")
7174
reader.ReadString('\n')
7275

7376
// Read temporary file back and rename files. Retry on fail.
7477
for {
75-
if err := readEntriesFile(filePath, fileEntries); err != nil {
76-
log.Printf("Failed to read temporary text file: %v", err)
77-
log.Print("Update the temporary text file and press any key to retry...")
78+
if err := readEntriesFile(filePath, fileEntries, numbering); err != nil {
79+
log.Printf("Failed to read filepaths: %v", err)
80+
log.Print("Please edit your filepaths, save them and press any key to retry...")
7881
reader.ReadString('\n')
7982
continue
8083
}
8184

8285
if err := moveFiles(fileEntries); err != nil {
8386
log.Printf("Failed to move file: %v", err)
84-
log.Print("Update the temporary file and press any key to retry...")
87+
log.Print("Please edit your filepaths, save them and press any key to retry...")
8588
reader.ReadString('\n')
8689
continue
8790
}
8891

8992
break
9093
}
9194

92-
log.Print("Deleting temporary file")
95+
log.Print("Deleting filepaths file")
9396

9497
// Try to delete the temporary file. Retry on fail.
9598
for {
9699
if err := os.Remove(filePath); err != nil {
97-
log.Printf("Failed to remove temporary text file: %v", err)
98-
log.Printf("Close the temporary text file and press any key to try again...")
100+
log.Printf("Failed to remove file with filepaths: %v", err)
101+
log.Printf("Please close your editor and press any key to try again...")
99102
reader.ReadString('\n')
100103
continue
101104
}

0 commit comments

Comments
 (0)