1 module dls.tools.formatter;
2 
3 import dfmt.config : BraceStyle;
4 import dfmt.editorconfig : EOL;
5 import dfmt.formatter;
6 import dls.tools.configuration : Configuration;
7 import dls.tools.tool : Tool;
8 
9 private immutable EOL[Configuration.FormatterConfiguration.EndOfLine] eolMap;
10 private immutable BraceStyle[Configuration.FormatterConfiguration.BraceStyle] braceStyleMap;
11 
12 static this()
13 {
14     //dfmt off
15     eolMap = [
16         Configuration.FormatterConfiguration.EndOfLine.lf   : EOL.lf,
17         Configuration.FormatterConfiguration.EndOfLine.cr   : EOL.cr,
18         Configuration.FormatterConfiguration.EndOfLine.crlf : EOL.crlf
19     ];
20 
21     braceStyleMap = [
22         Configuration.FormatterConfiguration.BraceStyle.allman     : BraceStyle.allman,
23         Configuration.FormatterConfiguration.BraceStyle.otbs       : BraceStyle.otbs,
24         Configuration.FormatterConfiguration.BraceStyle.stroustrup : BraceStyle.stroustrup
25     ];
26     //dfmt on
27 }
28 
29 class Formatter : Tool
30 {
31     import dls.protocol.interfaces : FormattingOptions;
32     import dls.util.uri : Uri;
33 
34     auto format(Uri uri, FormattingOptions options)
35     {
36         import dfmt.config : Config;
37         import dfmt.editorconfig : IndentStyle, OptionalBoolean;
38         import dls.protocol.definitions : TextEdit;
39         import dls.util.document : Document;
40         import std.outbuffer : OutBuffer;
41 
42         const document = Document[uri];
43         auto contents = cast(ubyte[]) document.toString();
44         auto config = Config();
45         auto buffer = new OutBuffer();
46         auto result = new TextEdit();
47 
48         result.range.end.line = document.lines.length;
49         result.range.end.character = document.lines[$ - 1].length;
50 
51         auto toOptBool(bool b)
52         {
53             return b ? OptionalBoolean.t : OptionalBoolean.f;
54         }
55 
56         config.indent_style = options.insertSpaces ? IndentStyle.space : IndentStyle.tab;
57         config.indent_size = cast(typeof(config.indent_size)) options.tabSize;
58         config.tab_width = config.indent_size;
59         config.end_of_line = eolMap[_configuration.formatter.endOfLine];
60         config.max_line_length = _configuration.formatter.maxLineLength;
61         config.dfmt_brace_style = braceStyleMap[_configuration.formatter.dfmtBraceStyle];
62         config.dfmt_soft_max_line_length = _configuration.formatter.dfmtSoftMaxLineLength;
63         config.dfmt_align_switch_statements = toOptBool(
64                 _configuration.formatter.dfmtAlignSwitchStatements);
65         config.dfmt_outdent_attributes = toOptBool(_configuration.formatter.dfmtOutdentAttributes);
66         config.dfmt_split_operator_at_line_end = toOptBool(
67                 _configuration.formatter.dfmtSplitOperatorAtLineEnd);
68         config.dfmt_space_after_cast = toOptBool(_configuration.formatter.dfmtSpaceAfterCast);
69         config.dfmt_space_after_keywords = toOptBool(
70                 _configuration.formatter.dfmtSpaceAfterKeywords);
71         config.dfmt_space_before_function_parameters = toOptBool(
72                 _configuration.formatter.dfmtSpaceBeforeFunctionParameters);
73         config.dfmt_selective_import_space = toOptBool(
74                 _configuration.formatter.dfmtSpaceBeforeFunctionParameters);
75         config.dfmt_compact_labeled_statements = _configuration.formatter.dfmtCompactLabeledStatements
76             ? OptionalBoolean.t : OptionalBoolean.f;
77 
78         dfmt.formatter.format(uri, contents, buffer, &config);
79         result.newText = buffer.toString();
80 
81         return [result];
82     }
83 }