123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- from std/os import join_path, nil
- from std/parseopt import nil
- from std/sugar import dup, collect, `=>`, `->`
- from std/osproc import wait_for_exit, nil
- from std/sequtils import to_seq, zip, filter, map_it, map
- from ./path import strip_paths
- from ./tmpdir import mktemp, mkdtemp
- from ./utils
- import die, warn, to_bool, to_int, all_uniq, exists, Exit, None
- type
- Config = object
- verbose: bool
- editor: string
- files: seq[string]
- proc get_config(): Config =
- var quiet: bool = false
- for kind, key, val in parseopt.getopt():
- case kind
- of parseopt.cmdArgument:
- result.files.add(key)
- of parseopt.cmdLongOption, parseopt.cmdShortOption:
- case key
- of "q", "quiet":
- quiet = true
- of "editor":
- if val:
- result.editor = val
- else:
- die("provide value for flag: ", key)
- else:
- die("invalid flag: ", key)
- of parseopt.cmdEnd: assert(false) # cannot happen
- result.verbose = not quiet
- if not result.editor:
- result.editor = os.get_env("EDITOR")
- if not result.editor:
- die "please, set editor throuth --editor flag or EDITOR env var"
- proc main(): int =
- let config = get_config()
- if not (config.files.len > 0):
- die "please provide some files to bulk rename"
- let dir = mkdtemp(prefix="brn.", suffix=".dir")
- try:
- let (fpath, file) = mktemp(tmpdir=dir, prefix="brn.", suffix=".files")
- try:
- let (prefix, files) = config.files.strip_paths
- if not files.all_uniq:
- die "found duplicate paths"
- discard file.dup(
- ((f: File) => (
- discard files.map do (i: string) -> None:
- f.write_line i
- )),
- flush_file,
- set_file_pos 0,
- )
- discard osproc.startProcess(
- command=config.editor,
- args=[fpath],
- options={
- osproc.poUsePath,
- osproc.poInteractive,
- osproc.poParentStreams,
- }
- ).wait_for_exit
- let new_files = file.lines.to_seq
- if new_files.len != files.len:
- die "different number of files before and after editing"
- for (old, new) in zip(files, new_files)
- .filter((x: tuple) => x[0] != x[1])
- .map((x: tuple) =>
- (prefix.join_path x[0], prefix.join_path x[1])):
- if not old.exists:
- warn "file did'n exists: " & old
- result = Exit.SomeErrors
- continue
- func `->`(o, n: auto): auto = o & " -> " & n
- try:
- os.move_file(old, new)
- if config.verbose: echo old -> new
- except OSError:
- warn "failed to rename: " & old -> new
- result = Exit.SomeErrors
- finally:
- file.close
- os.remove_file fpath
- finally:
- os.remove_dir dir
- when isMainModule: quit main()
|