rufo 0.0.31 → 0.0.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 208020c1cfc4ae639637febda545a3c3752980fe
4
- data.tar.gz: 17da5ed34f7765ff9e08daa305965e41c568a6ac
3
+ metadata.gz: 567434311fc51fc2df58435a9b746c8bceb677b6
4
+ data.tar.gz: 952b5fde3de3a1a1613b80da0f2b77a1bbf08883
5
5
  SHA512:
6
- metadata.gz: 696a53c1d4d30504a01c677fe87f54db384c68c8e8e38f510184c7bd2fd1bb4e9b18a04171b75318f722356bdcca93eef28e96feafb21d403336b0432d2821cc
7
- data.tar.gz: a5783f444cb5b20a2ef8d0b8eadd4a7e62502f4782e98bf5938ac484d6abbeda167384749a47b81ca10949c548e737a967706b420f64424225f94180bc753fb6
6
+ metadata.gz: c2922786da9e59ad5077d32fbe48b233416bf44d8c8e8719a02d73731ced2158f9051fb3e8fff8d1090d91d647e87e0b29cee7e58c8abcc73dcdc9fcdca239d4
7
+ data.tar.gz: 2c535a76bb09f8af19f0582873b58dab19b66d3fda4d784ad4dfc1e86dcf29539bd7f938ad0a0d916446e1ab18c67545e1d641bf186bbc2f72db324936c6bc62
data/README.md CHANGED
@@ -84,7 +84,7 @@ available configurations:
84
84
  # * :dynamic: if there's a space, keep it. If not, don't add it
85
85
  # * :always: always put a space after an array bracket (default)
86
86
  # * :never: never put a space after an array bracket
87
- space_after_array_bracket :never
87
+ space_after_array_bracket :dynamic
88
88
 
89
89
  # Whether to put a space after a hash brace. Valid values are:
90
90
  #
@@ -93,20 +93,20 @@ space_after_array_bracket :never
93
93
  # * :never: never put a space after a hash brace
94
94
  space_after_hash_brace :dynamic
95
95
 
96
- # Whether to align successive comments (default: true)
97
- align_comments true
96
+ # Whether to align successive comments (default: false)
97
+ align_comments false
98
98
 
99
99
  # Whether to align successive assignments (default: false)
100
100
  align_assignments false
101
101
 
102
- # Whether to align successive hash keys (default: true)
103
- align_hash_keys true
102
+ # Whether to align successive hash keys (default: false)
103
+ align_hash_keys false
104
104
 
105
- # Whether to align successive case when (default: true)
106
- align_case_when true
105
+ # Whether to align successive case when (default: false)
106
+ align_case_when false
107
107
 
108
- # Whether to align chained calls to the dot (default: true)
109
- align_chained_calls true
108
+ # Whether to align chained calls to the first dot in the first line (default: false)
109
+ align_chained_calls false
110
110
 
111
111
  # Preserve whitespace after assignments target and values,
112
112
  # after calls that start with a space, hash arrows and commas (default: true).
@@ -116,6 +116,12 @@ align_chained_calls true
116
116
  #
117
117
  # If `align_assignments` is true, this doesn't apply to assignments.
118
118
  # If `align_hash_keys` is true, this doesn't apply to hash keys.
119
+ #
120
+ #
121
+ # Can also be set to `:YES` to preserve whitespace in many more places,
122
+ # in case there's no clear rule in your workplace/project as to when
123
+ # to leave spaces or not. This includes spaces (or the absence of them)
124
+ # around dots, braces, pipes and hash keys and values.
119
125
  preserve_whitespace true
120
126
 
121
127
  # The indent size (default: 2)
@@ -123,10 +129,10 @@ indent_size 2
123
129
 
124
130
  # Whether to place commas at the end of a multi-line list
125
131
  #
126
- # * :dynamic: if there's a comma, keep it. If not, don't add it
127
- # * :always: always put a comma (default)
132
+ # * :dynamic: if there's a comma, keep it. If not, don't add it (default)
133
+ # * :always: always put a comma
128
134
  # * :never: never put a comma
129
- trailing_commas :always
135
+ trailing_commas :dyanmic
130
136
  ```
131
137
 
132
138
  As time passes there might be more configurations available. Please open an
@@ -26,6 +26,10 @@ class Rufo::Formatter
26
26
  # calls to that dot
27
27
  @dot_column = nil
28
28
 
29
+ # Same as above, but the column of the original dot, not
30
+ # the one we finally wrote
31
+ @original_dot_column = nil
32
+
29
33
  # Did this line already set the `@dot_column` variable?
30
34
  @line_has_dot_column = nil
31
35
 
@@ -68,6 +72,28 @@ class Rufo::Formatter
68
72
  # However, for these cases it's better to not align it like that.
69
73
  @line_to_call_info = {}
70
74
 
75
+ # Lists [first_line, last_line, indent] of lines that need an indent because
76
+ # of alignment of literals. For example this:#
77
+ #
78
+ # foo [
79
+ # 1,
80
+ # ]
81
+ #
82
+ # is normally formatted to:
83
+ #
84
+ # foo [
85
+ # 1,
86
+ # ]
87
+ #
88
+ # However, if it's already formatted like the above we preserve it.
89
+ @literal_indents = []
90
+
91
+ # First non-space token in this line
92
+ @first_token_in_line = nil
93
+
94
+ # Do we want to compute the above?
95
+ @want_first_token_in_line = false
96
+
71
97
  # Each line that belongs to a heredoc content is put here
72
98
  @heredoc_lines = {}
73
99
 
@@ -114,14 +140,14 @@ class Rufo::Formatter
114
140
  # Settings
115
141
  indent_size options.fetch(:indent_size, 2)
116
142
  space_after_hash_brace options.fetch(:space_after_hash_brace, :dynamic)
117
- space_after_array_bracket options.fetch(:space_after_array_bracket, :never)
118
- align_comments options.fetch(:align_comments, true)
143
+ space_after_array_bracket options.fetch(:space_after_array_bracket, :dynamic)
144
+ align_comments options.fetch(:align_comments, false)
119
145
  align_assignments options.fetch(:align_assignments, false)
120
- align_hash_keys options.fetch(:align_hash_keys, true)
121
- align_case_when options.fetch(:align_case_when, true)
122
- align_chained_calls options.fetch(:align_chained_calls, true)
146
+ align_hash_keys options.fetch(:align_hash_keys, false)
147
+ align_case_when options.fetch(:align_case_when, false)
148
+ align_chained_calls options.fetch(:align_chained_calls, false)
123
149
  preserve_whitespace options.fetch(:preserve_whitespace, true)
124
- trailing_commas options.fetch(:trailing_commas, :always)
150
+ trailing_commas options.fetch(:trailing_commas, :dynamic)
125
151
  end
126
152
 
127
153
  # The indent size (default: 2)
@@ -145,9 +171,9 @@ class Rufo::Formatter
145
171
 
146
172
  # Whether to put a space after an array bracket. Valid values are:
147
173
  #
148
- # * :dynamic: if there's a space, keep it. If not, don't keep it
174
+ # * :dynamic: if there's a space, keep it. If not, don't keep it (default)
149
175
  # * :always: always put a space after an array bracket
150
- # * :never: never put a space after an array bracket (default)
176
+ # * :never: never put a space after an array bracket
151
177
  def space_after_array_bracket(value)
152
178
  case value
153
179
  when :dynamic, :always, :never
@@ -157,7 +183,7 @@ class Rufo::Formatter
157
183
  end
158
184
  end
159
185
 
160
- # Whether to align successive comments (default: true)
186
+ # Whether to align successive comments (default: false)
161
187
  def align_comments(value)
162
188
  @align_comments = value
163
189
  end
@@ -167,17 +193,17 @@ class Rufo::Formatter
167
193
  @align_assignments = value
168
194
  end
169
195
 
170
- # Whether to align successive hash keys (default: true)
196
+ # Whether to align successive hash keys (default: false)
171
197
  def align_hash_keys(value)
172
198
  @align_hash_keys = value
173
199
  end
174
200
 
175
- # Whether to align successive case when (default: true)
201
+ # Whether to align successive case when (default: false)
176
202
  def align_case_when(value)
177
203
  @align_case_when = value
178
204
  end
179
205
 
180
- # Whether to align chained calls to the dot (default: true)
206
+ # Whether to align chained calls to the first dot in the first line (default: false)
181
207
  def align_chained_calls(value)
182
208
  @align_chained_calls = value
183
209
  end
@@ -190,14 +216,19 @@ class Rufo::Formatter
190
216
  #
191
217
  # If `align_assignments` is true, this doesn't apply to assignments.
192
218
  # If `align_hash_keys` is true, this doesn't apply to hash keys.
219
+ #
220
+ # Can also be set to `:YES` to preserve whitespace in many more places,
221
+ # in case there's no clear rule in your workplace/project as to when
222
+ # to leave spaces or not. This includes spaces (or the absence of them)
223
+ # around dots, braces, pipes and hash keys and values.
193
224
  def preserve_whitespace(value)
194
225
  @preserve_whitespace = value
195
226
  end
196
227
 
197
228
  # Whether to place commas at the end of a multi-line list
198
229
  #
199
- # * :dynamic: if there's a comma, keep it. If not, don't add it
200
- # * :always: always put a comma (default)
230
+ # * :dynamic: if there's a comma, keep it. If not, don't add it (default)
231
+ # * :always: always put a comma
201
232
  # * :never: never put a comma
202
233
  def trailing_commas(value)
203
234
  case value
@@ -215,6 +246,7 @@ class Rufo::Formatter
215
246
  @output.chomp! if @output.end_with?("\n\n")
216
247
 
217
248
  dedent_calls
249
+ indent_literals
218
250
  do_align_assignments if @align_assignments
219
251
  do_align_hash_keys if @align_hash_keys
220
252
  do_align_case_when if @align_case_when
@@ -806,8 +838,8 @@ class Rufo::Formatter
806
838
 
807
839
  def current_comment_aligned_to_previous_one?
808
840
  @last_comment &&
809
- @last_comment[0][0] + 1 == current_token[0][0] &&
810
- @last_comment[0][1] == current_token[0][1]
841
+ @last_comment[0][0] + 1 == current_token_line &&
842
+ @last_comment[0][1] == current_token_column
811
843
  end
812
844
 
813
845
  def track_comment(id: nil, match_previous_id: false)
@@ -912,25 +944,36 @@ class Rufo::Formatter
912
944
  @dot_column = nil
913
945
  visit obj
914
946
 
947
+ first_space = current_token if space? && @preserve_whitespace == :YES
915
948
  skip_space
916
949
 
917
950
  if newline? || comment?
918
951
  consume_end_of_line
919
952
 
920
- if @align_chained_calls
953
+ # If align_chained_calls if off, we still want to preserve alignment if it's already there
954
+ if @align_chained_calls || (@original_dot_column && @original_dot_column == current_token_column)
921
955
  @name_dot_column = @dot_column || next_indent
922
956
  write_indent(@dot_column || next_indent)
923
957
  else
958
+ # Make sure to reset dot_column so next lines don't align to the first dot
959
+ @dot_column = next_indent
924
960
  @name_dot_column = next_indent
925
961
  write_indent(next_indent)
926
962
  end
963
+ elsif first_space
964
+ write_space first_space[2]
927
965
  end
928
966
 
929
967
  # Remember dot column, but only if there isn't one already set
930
- dot_column = @column unless @dot_column
968
+ unless @dot_column
969
+ dot_column = @column
970
+ original_dot_column = current_token_column
971
+ end
931
972
 
932
973
  consume_call_dot
933
974
 
975
+ first_space = nil
976
+ first_space = current_token if space? && @preserve_whitespace == :YES
934
977
  skip_space
935
978
 
936
979
  if newline? || comment?
@@ -938,6 +981,9 @@ class Rufo::Formatter
938
981
  write_indent(next_indent)
939
982
  else
940
983
  skip_space_or_newline
984
+ if first_space
985
+ write_space first_space[2]
986
+ end
941
987
  end
942
988
 
943
989
  if name == :call
@@ -949,6 +995,7 @@ class Rufo::Formatter
949
995
  # Only set it after we visit the call after the dot,
950
996
  # so we remember the outmost dot position
951
997
  @dot_column = dot_column if dot_column
998
+ @original_dot_column = original_dot_column if original_dot_column
952
999
  end
953
1000
 
954
1001
  def consume_call_dot
@@ -975,6 +1022,8 @@ class Rufo::Formatter
975
1022
 
976
1023
  # Remember dot column so it's not affected by args
977
1024
  dot_column = @dot_column
1025
+ original_dot_column = @original_dot_column
1026
+
978
1027
  want_indent = @name_dot_column && @name_dot_column > @indent
979
1028
 
980
1029
  maybe_indent(want_indent, @name_dot_column) do
@@ -983,6 +1032,7 @@ class Rufo::Formatter
983
1032
 
984
1033
  # Restore dot column so it's not affected by args
985
1034
  @dot_column = dot_column
1035
+ @original_dot_column = original_dot_column
986
1036
  end
987
1037
 
988
1038
  def visit_call_at_paren(node, args)
@@ -1060,7 +1110,11 @@ class Rufo::Formatter
1060
1110
  skip_space_or_newline
1061
1111
  end
1062
1112
 
1063
- call_info << @line if call_info
1113
+ # If the closing parentheses matches the indent of the first parameter,
1114
+ # keep it like that. Otherwise dedent.
1115
+ if call_info && call_info[1] != current_token_column
1116
+ call_info << @line
1117
+ end
1064
1118
 
1065
1119
  consume_token :on_rparen
1066
1120
  end
@@ -1071,17 +1125,19 @@ class Rufo::Formatter
1071
1125
  # [:command, name, args]
1072
1126
  _, name, args = node
1073
1127
 
1128
+ base_column = current_token_column
1129
+
1074
1130
  push_call(node) do
1075
1131
  visit name
1076
1132
  consume_space_after_command_name
1077
1133
  end
1078
1134
 
1079
- visit_command_end(node, args)
1135
+ visit_command_end(node, args, base_column)
1080
1136
  end
1081
1137
 
1082
- def visit_command_end(node, args)
1138
+ def visit_command_end(node, args, base_column)
1083
1139
  push_call(node) do
1084
- visit_command_args(args)
1140
+ visit_command_args(args, base_column)
1085
1141
  end
1086
1142
  end
1087
1143
 
@@ -1117,11 +1173,19 @@ class Rufo::Formatter
1117
1173
  # [:args_add_block, [[:@int, "1", [1, 8]]], block]]
1118
1174
  _, receiver, dot, name, args = node
1119
1175
 
1176
+ base_column = current_token_column
1177
+
1120
1178
  visit receiver
1179
+
1180
+ first_space = current_token if space? && @preserve_whitespace == :YES
1181
+
1182
+ line = @line
1121
1183
  skip_space_or_newline
1122
1184
 
1123
1185
  # Remember dot column
1124
1186
  dot_column = @column
1187
+ original_dot_column = @original_dot_column
1188
+
1125
1189
  consume_call_dot
1126
1190
 
1127
1191
  skip_space
@@ -1135,11 +1199,12 @@ class Rufo::Formatter
1135
1199
 
1136
1200
  visit name
1137
1201
  consume_space_after_command_name
1138
- visit_command_args(args)
1202
+ visit_command_args(args, base_column)
1139
1203
 
1140
1204
  # Only set it after we visit the call after the dot,
1141
1205
  # so we remember the outmost dot position
1142
1206
  @dot_column = dot_column
1207
+ @original_dot_column = original_dot_column
1143
1208
  end
1144
1209
 
1145
1210
  def consume_space_after_command_name
@@ -1156,8 +1221,10 @@ class Rufo::Formatter
1156
1221
  end
1157
1222
  end
1158
1223
 
1159
- def visit_command_args(args)
1224
+ def visit_command_args(args, base_column)
1160
1225
  needed_indent = @column
1226
+ args_is_def_class_or_module = false
1227
+ param_column = current_token_column
1161
1228
 
1162
1229
  # Check if there's a single argument and it's
1163
1230
  # a def, class or module. In that case we don't
@@ -1171,11 +1238,13 @@ class Rufo::Formatter
1171
1238
  case first[0]
1172
1239
  when :def, :class, :module
1173
1240
  needed_indent = @indent
1241
+ args_is_def_class_or_module = true
1174
1242
  end
1175
1243
  end
1176
1244
  end
1177
1245
  end
1178
1246
 
1247
+ base_line = @line
1179
1248
  call_info = @line_to_call_info[@line]
1180
1249
  if call_info
1181
1250
  call_info = nil
@@ -1184,6 +1253,10 @@ class Rufo::Formatter
1184
1253
  @line_to_call_info[@line] = call_info
1185
1254
  end
1186
1255
 
1256
+ old_want_first_token_in_line = @want_first_token_in_line
1257
+ @want_first_token_in_line = true
1258
+
1259
+ # We align call parameters to the first paramter
1187
1260
  indent(needed_indent) do
1188
1261
  if args[0].is_a?(Symbol)
1189
1262
  visit args
@@ -1193,8 +1266,35 @@ class Rufo::Formatter
1193
1266
  end
1194
1267
 
1195
1268
  if call_info && call_info.size > 2
1269
+ # A call like:
1270
+ #
1271
+ # foo, 1, [
1272
+ # 2,
1273
+ # ]
1274
+ #
1275
+ # would normally be aligned like this (with the first parameter):
1276
+ #
1277
+ # foo, 1, [
1278
+ # 2,
1279
+ # ]
1280
+ #
1281
+ # However, the first style is valid too and we preserve it if it's
1282
+ # already formatted like that.
1196
1283
  call_info << @line
1284
+ elsif !args_is_def_class_or_module && @first_token_in_line && param_column == @first_token_in_line[0][1]
1285
+ # If the last line of the call is aligned with the first parameter, leave it like that:
1286
+ #
1287
+ # foo 1,
1288
+ # 2
1289
+ elsif !args_is_def_class_or_module && @first_token_in_line && base_column + @indent_size == @first_token_in_line[0][1]
1290
+ # Otherwise, align it just by two spaces (so we need to dedent, we fake a dedent here)
1291
+ #
1292
+ # foo 1,
1293
+ # 2
1294
+ @line_to_call_info[base_line] = [0, needed_indent - next_indent, true, @line, @line]
1197
1295
  end
1296
+
1297
+ @want_first_token_in_line = old_want_first_token_in_line
1198
1298
  end
1199
1299
 
1200
1300
  def visit_call_with_block(node)
@@ -1203,7 +1303,16 @@ class Rufo::Formatter
1203
1303
 
1204
1304
  visit call
1205
1305
 
1206
- consume_space
1306
+ if block[0] == :brace_block
1307
+ if space? || !@preserve_whitespace
1308
+ consume_space
1309
+ else
1310
+ consume_space unless @preserve_whitespace == :YES
1311
+ end
1312
+ else
1313
+ consume_space
1314
+ end
1315
+
1207
1316
  visit block
1208
1317
  end
1209
1318
 
@@ -1227,14 +1336,14 @@ class Rufo::Formatter
1227
1336
  closing_brace_token, index = find_closing_brace_token
1228
1337
 
1229
1338
  # If the whole block fits into a single line, use braces
1230
- if current_token[0][0] == closing_brace_token[0][0]
1339
+ if current_token_line == closing_brace_token[0][0]
1231
1340
  consume_token :on_lbrace
1232
1341
 
1233
1342
  consume_block_args args
1234
1343
 
1235
- consume_space
1344
+ consume_space unless !space? && @preserve_whitespace == :YES
1236
1345
  visit_exps body, with_lines: false
1237
- consume_space
1346
+ consume_space unless !space? && @preserve_whitespace == :YES
1238
1347
 
1239
1348
  consume_token :on_rbrace
1240
1349
  return
@@ -1251,7 +1360,11 @@ class Rufo::Formatter
1251
1360
  indent_body body, force_multiline: true
1252
1361
  write_indent
1253
1362
 
1254
- call_info << @line if call_info
1363
+ # If the closing bracket matches the indent of the first parameter,
1364
+ # keep it like that. Otherwise dedent.
1365
+ if call_info && call_info[1] != current_token_column
1366
+ call_info << @line
1367
+ end
1255
1368
 
1256
1369
  consume_token :on_rbrace
1257
1370
  end
@@ -1274,7 +1387,15 @@ class Rufo::Formatter
1274
1387
 
1275
1388
  def consume_block_args(args)
1276
1389
  if args
1277
- consume_space
1390
+ if space?
1391
+ consume_space(want_preserve_whitespace: @preserve_whitespace == :YES)
1392
+ else
1393
+ if @preserve_whitespace == :YES
1394
+ skip_space
1395
+ else
1396
+ consume_space
1397
+ end
1398
+ end
1278
1399
  # + 1 because of |...|
1279
1400
  # ^
1280
1401
  indent(@column + 1) do
@@ -1574,7 +1695,7 @@ class Rufo::Formatter
1574
1695
 
1575
1696
  # If the whole block fits into a single line, format
1576
1697
  # in a single line
1577
- if current_token[0][0] == closing_brace_token[0][0]
1698
+ if current_token_line == closing_brace_token[0][0]
1578
1699
  consume_token :on_lbrace
1579
1700
  consume_space
1580
1701
  visit_exps body, with_lines: false
@@ -1646,8 +1767,19 @@ class Rufo::Formatter
1646
1767
  _, before, star, after = node
1647
1768
 
1648
1769
  if before && !before.empty?
1649
- visit_comma_separated_list before
1650
- write_params_comma
1770
+ # Maybe a Ripper bug, but if there's something before a star
1771
+ # then a star shouldn't be here... but if it is... handle it
1772
+ # somehow...
1773
+ if current_token_kind == :on_op && current_token_value == "*"
1774
+ before, star, after = nil, before, after
1775
+ else
1776
+ if before[0].is_a?(Symbol)
1777
+ visit before
1778
+ else
1779
+ visit_comma_separated_list before
1780
+ end
1781
+ write_params_comma
1782
+ end
1651
1783
  end
1652
1784
 
1653
1785
  consume_op "*"
@@ -1715,6 +1847,8 @@ class Rufo::Formatter
1715
1847
  # right_exp
1716
1848
  # end
1717
1849
  needed_indent = @column == @indent ? next_indent : @column
1850
+ base_column = @column
1851
+ token_column = current_token_column
1718
1852
 
1719
1853
  visit left
1720
1854
  if space?
@@ -1736,7 +1870,7 @@ class Rufo::Formatter
1736
1870
  end
1737
1871
 
1738
1872
  consume_op_or_keyword op
1739
- indent_after_space right, want_space: needs_space, needed_indent: needed_indent
1873
+ indent_after_space right, want_space: needs_space, needed_indent: needed_indent, token_column: token_column, base_column: base_column
1740
1874
  end
1741
1875
 
1742
1876
  def consume_op_or_keyword(op)
@@ -2024,6 +2158,8 @@ class Rufo::Formatter
2024
2158
 
2025
2159
  _, elements = node
2026
2160
 
2161
+ token_column = current_token_column
2162
+
2027
2163
  check :on_lbracket
2028
2164
  write "["
2029
2165
  next_token
@@ -2034,7 +2170,7 @@ class Rufo::Formatter
2034
2170
  visit elements
2035
2171
  skip_space_or_newline
2036
2172
  else
2037
- visit_literal_elements elements, inside_array: true
2173
+ visit_literal_elements elements, inside_array: true, token_column: token_column
2038
2174
  end
2039
2175
  else
2040
2176
  skip_space_or_newline
@@ -2124,6 +2260,8 @@ class Rufo::Formatter
2124
2260
  # [:hash, elements]
2125
2261
  _, elements = node
2126
2262
 
2263
+ token_column = current_token_column
2264
+
2127
2265
  check :on_lbrace
2128
2266
  write "{"
2129
2267
  next_token
@@ -2131,7 +2269,7 @@ class Rufo::Formatter
2131
2269
  if elements
2132
2270
  # [:assoclist_from_args, elements]
2133
2271
  push_hash(node) do
2134
- visit_literal_elements(elements[1], inside_hash: true)
2272
+ visit_literal_elements(elements[1], inside_hash: true, token_column: token_column)
2135
2273
  end
2136
2274
  else
2137
2275
  skip_space_or_newline
@@ -2156,7 +2294,9 @@ class Rufo::Formatter
2156
2294
 
2157
2295
  visit key
2158
2296
 
2159
- consume_space(want_preserve_whitespace: @preserve_whitespace)
2297
+ unless @preserve_whitespace == :YES && !space? && !newline? && !comment?
2298
+ consume_space(want_preserve_whitespace: @preserve_whitespace)
2299
+ end
2160
2300
 
2161
2301
  track_hash_key
2162
2302
 
@@ -2164,7 +2304,10 @@ class Rufo::Formatter
2164
2304
  # or `"label": value`
2165
2305
  if arrow
2166
2306
  consume_op "=>"
2167
- consume_space(want_preserve_whitespace: !@align_hash_keys)
2307
+
2308
+ unless @preserve_whitespace == :YES && !space? && !newline? && !comment?
2309
+ consume_space(want_preserve_whitespace: !@align_hash_keys)
2310
+ end
2168
2311
  end
2169
2312
 
2170
2313
  visit value
@@ -2227,6 +2370,8 @@ class Rufo::Formatter
2227
2370
  def visit_array_getter_or_setter(name, args)
2228
2371
  visit name
2229
2372
 
2373
+ token_column = current_token_column
2374
+
2230
2375
  check :on_lbracket
2231
2376
  write "["
2232
2377
  next_token
@@ -2237,7 +2382,7 @@ class Rufo::Formatter
2237
2382
 
2238
2383
  # Sometimes args comes with an array...
2239
2384
  if args && args[0].is_a?(Array)
2240
- visit_literal_elements args
2385
+ visit_literal_elements args, token_column: token_column
2241
2386
  else
2242
2387
  if newline? || comment?
2243
2388
  needed_indent = next_indent
@@ -2287,18 +2432,30 @@ class Rufo::Formatter
2287
2432
  _, receiver, dot, name = node
2288
2433
 
2289
2434
  @dot_column = nil
2435
+ @original_dot_column = nil
2436
+
2290
2437
  visit receiver
2438
+
2439
+ first_space = current_token if space? && @preserve_whitespace == :YES
2440
+
2291
2441
  skip_space
2292
2442
 
2293
2443
  if newline? || comment?
2294
2444
  consume_end_of_line
2295
2445
 
2296
2446
  write_indent(@dot_column || next_indent)
2447
+ elsif first_space
2448
+ write_space first_space[2]
2297
2449
  end
2298
2450
 
2299
2451
  # Remember dot column
2300
2452
  dot_column = @column
2453
+ original_dot_column = current_token_column
2454
+
2301
2455
  consume_call_dot
2456
+
2457
+ first_space = nil
2458
+ first_space = current_token if space? && @preserve_whitespace == :YES
2302
2459
  skip_space
2303
2460
 
2304
2461
  if newline? || comment?
@@ -2306,6 +2463,9 @@ class Rufo::Formatter
2306
2463
  write_indent(next_indent)
2307
2464
  else
2308
2465
  skip_space_or_newline
2466
+ if first_space
2467
+ write_space first_space[2]
2468
+ end
2309
2469
  end
2310
2470
 
2311
2471
  visit name
@@ -2313,6 +2473,7 @@ class Rufo::Formatter
2313
2473
  # Only set it after we visit the call after the dot,
2314
2474
  # so we remember the outmost dot position
2315
2475
  @dot_column = dot_column
2476
+ @original_dot_column = original_dot_column
2316
2477
  end
2317
2478
 
2318
2479
  def visit_return(node)
@@ -2394,12 +2555,12 @@ class Rufo::Formatter
2394
2555
  closing_brace_token, index = find_closing_brace_token
2395
2556
 
2396
2557
  # Check if the whole block fits into a single line
2397
- if current_token[0][0] == closing_brace_token[0][0]
2558
+ if current_token_line == closing_brace_token[0][0]
2398
2559
  consume_token :on_tlambeg
2399
2560
 
2400
- consume_space
2561
+ consume_space unless !space? && @preserve_whitespace == :YES
2401
2562
  visit_exps body, with_lines: false
2402
- consume_space
2563
+ consume_space unless !space? && @preserve_whitespace == :YES
2403
2564
 
2404
2565
  consume_token :on_rbrace
2405
2566
  return
@@ -2425,11 +2586,13 @@ class Rufo::Formatter
2425
2586
  # [:super, args]
2426
2587
  _, args = node
2427
2588
 
2589
+ base_column = current_token_column
2590
+
2428
2591
  consume_keyword "super"
2429
2592
 
2430
2593
  if space?
2431
2594
  consume_space
2432
- visit_command_end node, args
2595
+ visit_command_end node, args, base_column
2433
2596
  else
2434
2597
  visit_call_at_paren node, args
2435
2598
  end
@@ -2486,8 +2649,9 @@ class Rufo::Formatter
2486
2649
  visit_comma_separated_list exps
2487
2650
  end
2488
2651
 
2489
- def visit_literal_elements(elements, inside_hash: false, inside_array: false)
2652
+ def visit_literal_elements(elements, inside_hash: false, inside_array: false, token_column:)
2490
2653
  base_column = @column
2654
+ base_line = @line
2491
2655
  needs_final_space = (inside_hash || inside_array) && space?
2492
2656
  skip_space
2493
2657
 
@@ -2605,7 +2769,20 @@ class Rufo::Formatter
2605
2769
  end
2606
2770
  end
2607
2771
 
2608
- call_info << @line if call_info
2772
+ if current_token_column == token_column && needed_indent < token_column
2773
+ # If the closing token is aligned with the opening token, we want to
2774
+ # keep it like that, for example in:
2775
+ #
2776
+ # foo([
2777
+ # 2,
2778
+ # ])
2779
+ @literal_indents << [base_line, @line, token_column + @indent_size - needed_indent]
2780
+ elsif call_info && call_info[0] == current_token_column
2781
+ # If the closing literal position matches the column where
2782
+ # the call started, we want to preserve it like that
2783
+ # (otherwise we align it to the first parameter)
2784
+ call_info << @line
2785
+ end
2609
2786
  end
2610
2787
 
2611
2788
  def check_heredocs_in_literal_elements(is_last, needs_trailing_comma, wrote_comma)
@@ -2718,11 +2895,16 @@ class Rufo::Formatter
2718
2895
  # [:when, conds, body, next_exp]
2719
2896
  _, conds, body, next_exp = node
2720
2897
 
2898
+ preserve_whitespace = @preserve_whitespace && !@align_case_when
2899
+
2721
2900
  consume_keyword "when"
2722
- consume_space
2901
+ consume_space(want_preserve_whitespace: preserve_whitespace)
2902
+
2903
+ space_after_when = nil
2723
2904
 
2724
2905
  indent(@column) do
2725
2906
  visit_comma_separated_list conds
2907
+ space_after_when = current_token if space? && preserve_whitespace
2726
2908
  skip_space
2727
2909
  end
2728
2910
 
@@ -2730,7 +2912,10 @@ class Rufo::Formatter
2730
2912
  inline = then_keyword || semicolon?
2731
2913
  if then_keyword
2732
2914
  next_token
2915
+
2916
+ space_after_then = current_token if space? && preserve_whitespace
2733
2917
  skip_space
2918
+
2734
2919
  track_case_when
2735
2920
  skip_semicolons
2736
2921
 
@@ -2740,7 +2925,19 @@ class Rufo::Formatter
2740
2925
  # Cancel tracking of `case when ... then` on a nelwine.
2741
2926
  @case_when_positions.pop
2742
2927
  else
2743
- write " then "
2928
+ if space_after_when
2929
+ write_space space_after_when[2]
2930
+ else
2931
+ write_space
2932
+ end
2933
+
2934
+ write "then"
2935
+
2936
+ if space_after_then
2937
+ write_space space_after_then[2]
2938
+ else
2939
+ write_space
2940
+ end
2744
2941
  end
2745
2942
  elsif semicolon?
2746
2943
  skip_semicolons
@@ -2913,11 +3110,12 @@ class Rufo::Formatter
2913
3110
  # - want_semicolon: do we want do print a semicolon to separate expressions?
2914
3111
  # - want_multiline: do we want multiple lines to appear, or at most one?
2915
3112
  def consume_end_of_line(at_prefix: false, want_semicolon: false, want_multiline: true, needs_two_lines_on_comment: false)
2916
- found_newline = false # Did we find any newline during this method?
2917
- last = nil # Last token kind found
2918
- multilple_lines = false # Did we pass through more than one newline?
2919
- last_comment_has_newline = false # Does the last comment has a newline?
2920
- newline_count = 0 # Number of newlines we passed
3113
+ found_newline = false # Did we find any newline during this method?
3114
+ found_comment_after_newline = false # Did we find a comment after some newline?
3115
+ last = nil # Last token kind found
3116
+ multilple_lines = false # Did we pass through more than one newline?
3117
+ last_comment_has_newline = false # Does the last comment has a newline?
3118
+ newline_count = 0 # Number of newlines we passed
2921
3119
 
2922
3120
  loop do
2923
3121
  case current_token_kind
@@ -2939,11 +3137,10 @@ class Rufo::Formatter
2939
3137
  else
2940
3138
  # If we just printed a comment that had a newline,
2941
3139
  # we must print two newlines because we remove newlines from comments (rstrip call)
3140
+ write_line
2942
3141
  if last == :comment && last_comment_has_newline
2943
- write_line
2944
3142
  multilple_lines = true
2945
3143
  else
2946
- write_line
2947
3144
  multilple_lines = false
2948
3145
  end
2949
3146
  end
@@ -3053,6 +3250,7 @@ class Rufo::Formatter
3053
3250
  @last_comment_column = @column
3054
3251
  last_comment_has_newline = current_token_value.end_with?("\n")
3055
3252
  last = :comment
3253
+ found_comment_after_newline = found_newline
3056
3254
  multilple_lines = false
3057
3255
 
3058
3256
  write current_token_value.rstrip
@@ -3074,7 +3272,7 @@ class Rufo::Formatter
3074
3272
  # or we just passed multiple lines (but printed only one)
3075
3273
  if (!found_newline && !at_prefix && !(want_semicolon && last == :semicolon)) ||
3076
3274
  last == :comment ||
3077
- (multilple_lines && want_multiline)
3275
+ (multilple_lines && (want_multiline || found_comment_after_newline))
3078
3276
  write_line
3079
3277
  end
3080
3278
  end
@@ -3095,7 +3293,7 @@ class Rufo::Formatter
3095
3293
  def consume_end
3096
3294
  return unless current_token_kind == :on___end__
3097
3295
 
3098
- line = current_token[0][0]
3296
+ line = current_token_line
3099
3297
 
3100
3298
  write_line
3101
3299
  consume_token :on___end__
@@ -3225,7 +3423,7 @@ class Rufo::Formatter
3225
3423
  @column += indent
3226
3424
  end
3227
3425
 
3228
- def indent_after_space(node, sticky: false, want_space: true, first_space: nil, needed_indent: next_indent)
3426
+ def indent_after_space(node, sticky: false, want_space: true, first_space: nil, needed_indent: next_indent, token_column: nil, base_column: nil)
3229
3427
  first_space = current_token if space?
3230
3428
 
3231
3429
  skip_space
@@ -3233,8 +3431,19 @@ class Rufo::Formatter
3233
3431
  when :on_ignored_nl, :on_comment
3234
3432
  indent(needed_indent) do
3235
3433
  consume_end_of_line
3236
- write_indent
3237
- visit node
3434
+ end
3435
+
3436
+ if token_column && base_column && token_column == current_token_column
3437
+ # If the expression is aligned with the one above, keep it like that
3438
+ indent(base_column) do
3439
+ write_indent
3440
+ visit node
3441
+ end
3442
+ else
3443
+ indent(needed_indent) do
3444
+ write_indent
3445
+ visit node
3446
+ end
3238
3447
  end
3239
3448
  else
3240
3449
  if want_space
@@ -3283,6 +3492,14 @@ class Rufo::Formatter
3283
3492
  tok ? tok[2] : ""
3284
3493
  end
3285
3494
 
3495
+ def current_token_line
3496
+ current_token[0][0]
3497
+ end
3498
+
3499
+ def current_token_column
3500
+ current_token[0][1]
3501
+ end
3502
+
3286
3503
  def keyword?(kw)
3287
3504
  current_token_kind == :on_kw && current_token_value == kw
3288
3505
  end
@@ -3347,11 +3564,26 @@ class Rufo::Formatter
3347
3564
  end
3348
3565
 
3349
3566
  def next_token
3567
+ prev_token = self.current_token
3568
+
3350
3569
  @tokens.pop
3351
3570
 
3352
3571
  if (newline? || comment?) && !@heredocs.empty?
3353
3572
  flush_heredocs
3354
3573
  end
3574
+
3575
+ # First first token in newline if requested
3576
+ if @want_first_token_in_line && prev_token && (prev_token[1] == :on_nl || prev_token[1] == :on_ignored_nl)
3577
+ @tokens.reverse_each do |token|
3578
+ case token[1]
3579
+ when :on_sp
3580
+ next
3581
+ else
3582
+ @first_token_in_line = token
3583
+ break
3584
+ end
3585
+ end
3586
+ end
3355
3587
  end
3356
3588
 
3357
3589
  def next_token_no_heredoc_check
@@ -3420,6 +3652,25 @@ class Rufo::Formatter
3420
3652
  @output = lines.join
3421
3653
  end
3422
3654
 
3655
+ def indent_literals
3656
+ return if @literal_indents.empty?
3657
+
3658
+ lines = @output.lines
3659
+
3660
+ @literal_indents.each do |first_line, last_line, indent|
3661
+ (first_line + 1..last_line).each do |line|
3662
+ next if @heredoc_lines[line]
3663
+
3664
+ current_line = lines[line]
3665
+ current_line = "#{" " * indent}#{current_line}"
3666
+ lines[line] = current_line
3667
+ adjust_other_alignments nil, line, 0, indent
3668
+ end
3669
+ end
3670
+
3671
+ @output = lines.join
3672
+ end
3673
+
3423
3674
  def do_align_comments
3424
3675
  do_align @comments_positions, :comment
3425
3676
  end
data/lib/rufo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Rufo
2
- VERSION = "0.0.31"
2
+ VERSION = "0.0.32"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rufo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.31
4
+ version: 0.0.32
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ary Borenszweig
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-06-30 00:00:00.000000000 Z
11
+ date: 2017-07-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler