@@ -1204,6 +1204,12 @@ defmodule Code do
1204
1204
* `:emit_warnings` (since v1.16.0) - when `false`, does not emit
1205
1205
tokenizing/parsing related warnings. Defaults to `true`.
1206
1206
1207
+ * `:include_comments` (since v1.19.0) - when `true`, includes comments
1208
+ in the quoted form. Defaults to `false`. If this option is set to
1209
+ `true`, the `:literal_encoder` option must be set to a function
1210
+ that ensures all literals are annotated, for example
1211
+ `&{:ok, {:__block__, &2, [&1]}}`.
1212
+
1207
1213
## `Macro.to_string/2`
1208
1214
1209
1215
The opposite of converting a string to its quoted form is
@@ -1243,21 +1249,87 @@ defmodule Code do
1243
1249
* atoms used to represent single-letter sigils like `:sigil_X`
1244
1250
(but multi-letter sigils like `:sigil_XYZ` are encoded).
1245
1251
1252
+ ## Comments
1253
+
1254
+ When `include_comments: true` is passed, comments are included in the
1255
+ quoted form.
1256
+
1257
+ There are three types of comments:
1258
+ - `:leading_comments`: Comments that are located before a node,
1259
+ or in the same line.
1260
+
1261
+ Examples:
1262
+
1263
+ # This is a leading comment
1264
+ foo # This one too
1265
+
1266
+ - `:trailing_comments`: Comments that are located after a node, and
1267
+ before the end of the parent enclosing the node(or the root document).
1268
+
1269
+ Examples:
1270
+
1271
+ foo
1272
+ # This is a trailing comment
1273
+ # This one too
1274
+
1275
+ - `:inner_comments`: Comments that are located inside an empty node.
1276
+
1277
+ Examples:
1278
+
1279
+ foo do
1280
+ # This is an inner comment
1281
+ end
1282
+
1283
+ [
1284
+ # This is an inner comment
1285
+ ]
1286
+
1287
+ %{
1288
+ # This is an inner comment
1289
+ }
1290
+
1291
+ A comment may be considered inner or trailing depending on wether the enclosing
1292
+ node is empty or not. For example, in the following code:
1293
+
1294
+ foo do
1295
+ # This is an inner comment
1296
+ end
1297
+
1298
+ The comment is considered inner because the `do` block is empty. However, in the
1299
+ following code:
1300
+
1301
+ foo do
1302
+ bar
1303
+ # This is a trailing comment
1304
+ end
1305
+
1306
+ The comment is considered trailing to `bar` because the `do` block is not empty.
1307
+
1308
+ In the case no nodes are present in the AST but there are comments, they are
1309
+ inserted into a placeholder `:__block__` node as `:inner_comments`.
1246
1310
"""
1247
1311
@ spec string_to_quoted ( List.Chars . t ( ) , keyword ) ::
1248
1312
{ :ok , Macro . t ( ) } | { :error , { location :: keyword , binary | { binary , binary } , binary } }
1249
1313
def string_to_quoted ( string , opts \\ [ ] ) when is_list ( opts ) do
1250
1314
file = Keyword . get ( opts , :file , "nofile" )
1251
1315
line = Keyword . get ( opts , :line , 1 )
1252
1316
column = Keyword . get ( opts , :column , 1 )
1253
- include_comments = Keyword . get ( opts , :include_comments , false )
1317
+ include_comments? = Keyword . get ( opts , :include_comments , false )
1254
1318
1255
1319
Process . put ( :code_formatter_comments , [ ] )
1256
- opts = [ preserve_comments: & preserve_comments / 5 ] ++ opts
1320
+ opts =
1321
+ if include_comments? do
1322
+ [
1323
+ preserve_comments: & preserve_comments / 5 ,
1324
+ token_metadata: true ,
1325
+ ] ++ opts
1326
+ else
1327
+ opts
1328
+ end
1257
1329
1258
1330
with { :ok , tokens } <- :elixir . string_to_tokens ( to_charlist ( string ) , line , column , file , opts ) ,
1259
1331
{ :ok , quoted } <- :elixir . tokens_to_quoted ( tokens , file , opts ) do
1260
- if include_comments do
1332
+ if include_comments? do
1261
1333
quoted = Code.Normalizer . normalize ( quoted )
1262
1334
quoted = Code.Comments . merge_comments ( quoted , Process . get ( :code_formatter_comments ) )
1263
1335
@@ -1287,26 +1359,23 @@ defmodule Code do
1287
1359
file = Keyword . get ( opts , :file , "nofile" )
1288
1360
line = Keyword . get ( opts , :line , 1 )
1289
1361
column = Keyword . get ( opts , :column , 1 )
1290
- include_comments = Keyword . get ( opts , :include_comments , false )
1362
+ include_comments? = Keyword . get ( opts , :include_comments , false )
1291
1363
1292
1364
Process . put ( :code_formatter_comments , [ ] )
1293
1365
1294
- opts =
1295
- if include_comments do
1296
- [ preserve_comments: & preserve_comments / 5 ,
1297
- literal_encoder: & { :ok , { :__block__ , & 2 , [ & 1 ] } } ,
1298
- token_metadata: true ,
1299
- unescape: false ,
1300
- columns: true ,
1301
- ] ++ opts
1366
+ opts =
1367
+ if include_comments? do
1368
+ [
1369
+ preserve_comments: & preserve_comments / 5 ,
1370
+ token_metadata: true ,
1371
+ ] ++ opts
1302
1372
else
1303
1373
opts
1304
1374
end
1305
1375
1306
1376
quoted = :elixir . string_to_quoted! ( to_charlist ( string ) , line , column , file , opts )
1307
1377
1308
- if include_comments do
1309
- # quoted = Code.Normalizer.normalize(quoted)
1378
+ if include_comments? do
1310
1379
Code.Comments . merge_comments ( quoted , Process . get ( :code_formatter_comments ) )
1311
1380
else
1312
1381
quoted
0 commit comments