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 }