Merge: doc: fixed some typos and other misc. corrections
[nit.git] / src / nitpretty.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # `nitpretty` is a tool able to pretty print Nit files.
16 #
17 # See `man nitpretty` for more infos.
18 import pretty
19
20 redef class ToolContext
21 # The working directory used to store temp files.
22 var opt_dir = new OptionString("Working directory (default is '.nitpretty')", "--dir")
23
24 # Output pretty printed code with this filename.
25 var opt_output = new OptionString("Output name (default is pretty.nit)", "-o",
26 "--output")
27
28 # Show diff between source and pretty printed code.
29 var opt_diff = new OptionBool("Show diff between source and output", "--diff")
30
31 # Show diff between source and pretty printed code using meld.
32 var opt_meld = new OptionBool("Show diff between source and output using meld",
33 "--meld")
34
35 # --line-width
36 var opt_line_width = new OptionInt("Maximum length of lines (use 0 to disable automatic line breaks)", 80, "--line-width")
37
38 # --no-inline
39 var opt_no_inline = new OptionBool("Disable automatic one-liners", "--no-inline")
40
41 # Break too long string literals.
42 var opt_break_str = new OptionBool("Break too long string literals", "--break-strings")
43
44 # Force `do` on the same line as the method signature.
45 var opt_inline_do = new OptionBool("Force do keyword on the same line as the method signature",
46 "--inline-do")
47
48 # Force formatting on empty lines.
49 #
50 # By default empty lines are kept as they were typed in the file.
51 # When enabling this option, `nitpretty` will decide where to break lines
52 # and will put empty lines to separate properties and code blocks.
53 var opt_skip_empty = new OptionBool("Force formatting of empty lines", "--skip-empty")
54
55 # Check formatting instead of pretty printing.
56 #
57 # This option creates a temporary pretty printed file then checks if the
58 # output of the diff command on the source file and the pretty printed one is
59 # empty.
60 var opt_check = new OptionBool("Check format of Nit source files", "--check")
61 end
62
63 # Return result from diff between `file1` and `file2`.
64 private fun diff(file1, file2: String): String do
65 var p = new ProcessReader("diff", "-u", file1, file2)
66 var res = p.read_all
67 p.wait
68 p.close
69 return res
70 end
71
72 # process options
73 var toolcontext = new ToolContext
74
75 var opts = toolcontext.option_context
76 opts.add_option(toolcontext.opt_dir, toolcontext.opt_output)
77 opts.add_option(toolcontext.opt_diff, toolcontext.opt_meld, toolcontext.opt_check)
78 opts.add_option(toolcontext.opt_line_width, toolcontext.opt_break_str, toolcontext.opt_inline_do)
79 opts.add_option(toolcontext.opt_no_inline)
80 opts.add_option(toolcontext.opt_skip_empty)
81
82 toolcontext.tooldescription = "Usage: nitpretty [OPTION]... <file.nit>\n" +
83 "Pretty print Nit code from Nit source files."
84
85 toolcontext.process_options args
86 var arguments = toolcontext.option_context.rest
87 # build model
88 var model = new Model
89 var mbuilder = new ModelBuilder(model, toolcontext)
90 var mmodules = mbuilder.parse_full(arguments)
91 mbuilder.run_phases
92
93 if mmodules.is_empty then
94 print "Error: no module to pretty print"
95 return
96 end
97
98 if not toolcontext.opt_check.value and mmodules.length > 1 then
99 print "Error: only --check option allow multiple modules"
100 return
101 end
102
103 var dir = toolcontext.opt_dir.value or else ".nitpretty"
104 if not dir.file_exists then dir.mkdir
105 var v = new PrettyPrinterVisitor
106
107 v.max_size = toolcontext.opt_line_width.value
108 if toolcontext.opt_break_str.value then
109 v.break_strings = true
110 end
111 if toolcontext.opt_inline_do.value then
112 v.inline_do = true
113 end
114 if toolcontext.opt_skip_empty.value then
115 v.skip_empty = true
116 end
117 if toolcontext.opt_no_inline.value then
118 v.no_inline = true
119 end
120
121 for mmodule in mmodules do
122 var nmodule = mbuilder.mmodule2node(mmodule)
123 if nmodule == null then
124 print " Error: no source file for module {mmodule}"
125 return
126 end
127 var file = "{dir}/{mmodule.name}.nit"
128 var tpl = v.pretty_nmodule(nmodule)
129 tpl.write_to_file file
130
131 if toolcontext.opt_check.value then
132 var res = diff(nmodule.location.file.filename, file)
133
134 if not res.is_empty then
135 print "Wrong formating for module {nmodule.location.file.filename}"
136 toolcontext.info(res, 1)
137
138 if toolcontext.opt_meld.value then
139 sys.system "meld {nmodule.location.file.filename} {file}"
140 end
141 else
142 toolcontext.info("[OK] {nmodule.location.file.filename}", 1)
143 end
144 else
145 # write to file
146 var out = toolcontext.opt_output.value
147 if out != null then sys.system "cp {file} {out}"
148
149 # open in meld
150 if toolcontext.opt_meld.value then
151 sys.system "meld {arguments.first} {file}"
152 return
153 end
154
155 # show diff
156 if toolcontext.opt_diff.value then
157 var res = diff(arguments.first, file)
158 if not res.is_empty then print res
159 return
160 end
161
162 # show pretty
163 if not toolcontext.opt_quiet.value then tpl.write_to sys.stdout
164 end
165 end