1 /* Distributed under the Boost Software License, Version 1.0.
2  *    (See accompanying file LICENSE_1_0.txt or copy at
3  *          http://www.boost.org/LICENSE_1_0.txt)
4  */
5 
6 /* Replace tabs with spaces, and remove trailing whitespace from lines.
7  */
8 
9 // Derived from git://github.com/D-Programming-Language/tools.git
10 module autoformat.tool_detab;
11 
12 import std.file;
13 import std.path;
14 import std.typecons : Flag;
15 import logger = std.experimental.logger;
16 
17 import autoformat.types;
18 
19 auto runDetab(AbsolutePath fname, Flag!"backup" backup, Flag!"dryRun" dry_run) nothrow {
20     auto rval = FormatterResult(FormatError.init);
21 
22     char[] input;
23     try {
24         input = cast(char[]) std.file.read(cast(string) fname);
25     } catch (Exception ex) {
26         rval = FailedWithUserMsg(ex.msg);
27         return rval;
28     }
29 
30     char[] output;
31     try {
32         output = filter(input);
33     } catch (Exception e) {
34         rval = WouldChange.init;
35         return rval;
36     }
37 
38     if (input == output) {
39         rval = Unchanged.init;
40         return rval;
41     }
42 
43     if (dry_run) {
44         rval = WouldChange.init;
45         return rval;
46     }
47 
48     try {
49         if (backup) {
50             copy(fname, fname.toString ~ ".orig");
51         }
52 
53         std.file.write(fname, output);
54         rval = FormattedOk.init;
55     } catch (Exception ex) {
56         rval = FailedWithUserMsg(ex.msg);
57     }
58 
59     return rval;
60 }
61 
62 char[] filter(char[] input) {
63     char[] output;
64     size_t j;
65 
66     int column;
67     for (size_t i = 0; i < input.length; i++) {
68         auto c = input[i];
69 
70         switch (c) {
71         case '\t':
72             while ((column & 7) != 7) {
73                 output ~= ' ';
74                 j++;
75                 column++;
76             }
77             c = ' ';
78             column++;
79             break;
80 
81         case '\r':
82         case '\n':
83             while (j && output[j - 1] == ' ')
84                 j--;
85             output = output[0 .. j];
86             column = 0;
87             break;
88 
89         default:
90             column++;
91             break;
92         }
93         output ~= c;
94         j++;
95     }
96     while (j && output[j - 1] == ' ')
97         j--;
98     return output[0 .. j];
99 }