├── .gitignore ├── morepretty.nimble ├── README.md └── src └── morepretty.nim /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore files with no extention: 2 | * 3 | !*/ 4 | !*.* 5 | 6 | # normal ignores: 7 | *.exe 8 | nimcache 9 | -------------------------------------------------------------------------------- /morepretty.nimble: -------------------------------------------------------------------------------- 1 | # Package 2 | 3 | version = "0.1.0" 4 | author = "Andre von Houck" 5 | description = "morepretty - More pretty than nimpretty." 6 | license = "MIT" 7 | srcDir = "src" 8 | 9 | # Dependencies 10 | 11 | requires "nim >= 1.0.0" 12 | 13 | bin = @["morepretty"] 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # morepretty - More pretty than nimpretty. 2 | 3 | `nimble install morepretty` 4 | 5 | This command line has no dependencies other than the Nim standard library. 6 | 7 | ## nimpretty does not ... 8 | 9 | * organize imports 10 | * remove blank lines 11 | * convert windows to unix line endings 12 | * insert a single line at the end of files for git 13 | * pretty the whole dir tree at once 14 | 15 | **so morepretty does all of that!** 16 | 17 | `morepretty` runs `nimpretty` too so you only ever need to run one command to format your code. 18 | -------------------------------------------------------------------------------- /src/morepretty.nim: -------------------------------------------------------------------------------- 1 | import algorithm, os, osproc, sequtils, sets, strutils 2 | 3 | proc formatLines(input: seq[string]): seq[string] = 4 | ## Remove \r and excess blank lines. 5 | var 6 | blankLines = 0 7 | 8 | for i, line in input: 9 | var line = line.replace("\r", "") 10 | if line.strip() == "": 11 | if blankLines > 0 or i == 0: 12 | continue 13 | inc blankLines 14 | else: 15 | blankLines = 0 16 | 17 | if line[^1] == ';': 18 | line = line[0..^2] 19 | 20 | result.add(line) 21 | 22 | proc importsExports(s: var seq[string], line: string) = 23 | for lib in line.split(","): 24 | let lib = lib.strip() 25 | if lib.len > 0: 26 | s.add(lib) 27 | 28 | proc processFile(filePath: string) = 29 | ## More-pretty a file. 30 | var 31 | imports, exports: seq[string] ## List of imports in the block. 32 | next: seq[string] ## Set of modified lines passed to next step. 33 | output: seq[string] ## Building output lines in this file. 34 | input = readFile(filePath).split("\n") 35 | firstImportLine = len(input) 36 | firstExportLine = len(input) 37 | importNextLineToo = false ## Should import next line? 38 | exportNextLineToo = false 39 | 40 | # Find all imports at the top of the file (possibly across multiple lines) 41 | # Add all not import and export lines to next 42 | for i, line in input: 43 | if importNextLineToo: 44 | importsExports(imports, line) 45 | importNextLineToo = false 46 | if line.endsWith(","): 47 | importNextLineToo = true 48 | elif exportNextLineToo: 49 | importsExports(exports, line) 50 | exportNextLineToo = false 51 | if line.endsWith(","): 52 | exportNextLineToo = true 53 | elif line.startsWith("import") and "except" notin line: 54 | firstImportLine = min(i, firstImportLine) 55 | importsExports(imports, line[6..^1]) 56 | if line.endsWith(","): 57 | importNextLineToo = true 58 | elif line.startsWith("export") and "except" notin line: 59 | firstExportLine = min(i, firstExportLine) 60 | importsExports(exports, line[6..^1]) 61 | if line.endsWith(","): 62 | exportNextLineToo = true 63 | else: 64 | next.add(line) 65 | 66 | # Holds the entire file with "import " lines stripped out 67 | next = formatLines(next) 68 | 69 | proc writeSorted(label: string, items: seq[string]): string = 70 | var items = toSeq(toHashSet(items)) # Remove duplicates 71 | items.sort() 72 | label & items.join(", ") 73 | 74 | proc writeImports() = 75 | # Add excess blank lines that are removed later 76 | output.add("") 77 | output.add(writeSorted("import ", imports)) 78 | output.add("") 79 | imports.setLen(0) 80 | 81 | proc writeExports() = 82 | # Add excess blank lines that are removed later 83 | output.add("") 84 | output.add(writeSorted("export ", exports)) 85 | output.add("") 86 | exports.setLen(0) 87 | 88 | for i, line in next: 89 | # File comments before imports (must have come before first import line) 90 | if (line.startsWith("#") or line == "") and i < firstImportLine: 91 | output.add(line) 92 | continue 93 | 94 | # Add imports back after file comments 95 | if imports.len > 0: 96 | writeImports() 97 | 98 | # Any comments before exports (must have come before first export line) 99 | if (line.startsWith("#") or line == "") and i < firstExportLine: 100 | output.add(line) 101 | continue 102 | 103 | # Add exports back 104 | if exports.len > 0: 105 | writeExports() 106 | 107 | output.add(line) 108 | 109 | # In the case we've removed enough lines that these never have chance to get 110 | # written. This isn't likely but can happen. 111 | if len(imports) > 0: 112 | writeImports() 113 | if len(exports) > 0: 114 | writeExports() 115 | 116 | output = formatLines(output) 117 | 118 | writeFile(filePath, output.join("\n").strip(leading = false) & "\n") 119 | discard execCmdEx("nimpretty --indent:2 " & filePath) 120 | 121 | # Walk thorugh all .nim files in this and sub dirs. 122 | for f in walkDirRec(getCurrentDir()): 123 | if f.endsWith(".nim"): 124 | echo f 125 | processFile(f) 126 | --------------------------------------------------------------------------------