@@ -1273,57 +1273,50 @@ answer_color(r::StreamREPL) = r.answer_color
1273
1273
input_color (r:: LineEditREPL ) = r. envcolors ? Base. input_color () : r. input_color
1274
1274
input_color (r:: StreamREPL ) = r. input_color
1275
1275
1276
- # heuristic function to decide if the presence of a semicolon
1277
- # at the end of the expression was intended for suppressing output
1278
- function ends_with_semicolon (line:: AbstractString )
1279
- match = findlast (isequal (' ;' ), line):: Union{Nothing,Int}
1280
- if match != = nothing
1281
- # state for comment parser, assuming that the `;` isn't in a string or comment
1282
- # so input like ";#" will still thwart this to give the wrong (anti-conservative) answer
1283
- comment = false
1284
- comment_start = false
1285
- comment_close = false
1286
- comment_multi = 0
1287
- for c in line[(match + 1 ): end ]
1288
- if comment_multi > 0
1289
- # handle nested multi-line comments
1290
- if comment_close && c == ' #'
1291
- comment_close = false
1292
- comment_multi -= 1
1293
- elseif comment_start && c == ' ='
1294
- comment_start = false
1295
- comment_multi += 1
1296
- else
1297
- comment_start = (c == ' #' )
1298
- comment_close = (c == ' =' )
1299
- end
1300
- elseif comment
1301
- # handle line comments
1302
- if c == ' \r ' || c == ' \n '
1303
- comment = false
1276
+ let matchend = Dict (" \" " => r" \" " , " \"\"\" " => r" \"\"\" " , " '" => r" '" ,
1277
+ " `" => r" `" , " ```" => r" ```" , " #" => r" $" m , " #=" => r" =#|#=" )
1278
+ global _rm_strings_and_comments
1279
+ function _rm_strings_and_comments (code:: Union{String,SubString{String}} )
1280
+ buf = IOBuffer (sizehint = sizeof (code))
1281
+ pos = 1
1282
+ while true
1283
+ i = findnext (r" \" (?!\"\" )|\"\"\" |'|`(?!``)|```|#(?!=)|#=" , code, pos)
1284
+ isnothing (i) && break
1285
+ match = SubString (code, i)
1286
+ j = findnext (matchend[match]:: Regex , code, nextind (code, last (i)))
1287
+ if match == " #=" # possibly nested
1288
+ nested = 1
1289
+ while j != = nothing
1290
+ nested += SubString (code, j) == " #=" ? + 1 : - 1
1291
+ iszero (nested) && break
1292
+ j = findnext (r" =#|#=" , code, nextind (code, last (j)))
1304
1293
end
1305
- elseif comment_start
1306
- # see what kind of comment this is
1307
- comment_start = false
1308
- if c == ' ='
1309
- comment_multi = 1
1310
- else
1311
- comment = true
1294
+ elseif match[1 ] != ' #' # quote match: check non-escaped
1295
+ while j != = nothing
1296
+ notbackslash = findprev (!= (' \\ ' ), code, prevind (code, first (j))):: Int
1297
+ isodd (first (j) - notbackslash) && break # not escaped
1298
+ j = findnext (matchend[match]:: Regex , code, nextind (code, first (j)))
1312
1299
end
1313
- elseif c == ' #'
1314
- # start handling for a comment
1315
- comment_start = true
1300
+ end
1301
+ isnothing (j) && break
1302
+ if match[1 ] == ' #'
1303
+ print (buf, SubString (code, pos, prevind (code, first (i))))
1316
1304
else
1317
- # outside of a comment, encountering anything but whitespace
1318
- # means the semi-colon was internal to the expression
1319
- isspace (c) || return false
1305
+ print (buf, SubString (code, pos, last (i)), ' ' , SubString (code, j))
1320
1306
end
1307
+ pos = nextind (code, last (j))
1321
1308
end
1322
- return true
1309
+ print (buf, SubString (code, pos, lastindex (code)))
1310
+ return String (take! (buf))
1323
1311
end
1324
- return false
1325
1312
end
1326
1313
1314
+ # heuristic function to decide if the presence of a semicolon
1315
+ # at the end of the expression was intended for suppressing output
1316
+ ends_with_semicolon (code:: AbstractString ) = ends_with_semicolon (String (code))
1317
+ ends_with_semicolon (code:: Union{String,SubString{String}} ) =
1318
+ contains (_rm_strings_and_comments (code), r" ;\s *$" )
1319
+
1327
1320
function run_frontend (repl:: StreamREPL , backend:: REPLBackendRef )
1328
1321
have_color = hascolor (repl)
1329
1322
Base. banner (repl. stream)
0 commit comments