Perf: Do not split source into lines at every fix

This commit is contained in:
Jeroen Engels 2019-08-04 12:38:23 +02:00
parent 9e6160f8a6
commit c5d706f739

View File

@ -77,7 +77,8 @@ fix : List Fix -> String -> String
fix fixes sourceCode =
fixes
|> List.sortBy (rangePosition >> negate)
|> List.foldl applyFix sourceCode
|> List.foldl applyFix (String.lines sourceCode)
|> String.join "\n"
rangePosition : Fix -> Int
@ -101,6 +102,86 @@ rangePosition fix_ =
row * 1000000 + column
comparePosition : { row : Int, column : Int } -> { row : Int, column : Int } -> Order
comparePosition a b =
let
order : Order
order =
compare a.row b.row
in
case order of
EQ ->
compare a.column b.column
_ ->
order
applyFix : Fix -> List String -> List String
applyFix fix_ lines =
lines
|> (case fix_ of
Replacement range replacement ->
applyReplace range replacement
Removal range ->
applyReplace range ""
InsertAt position insertion ->
applyReplace { start = position, end = position } insertion
)
applyReplace : Range -> String -> List String -> List String
applyReplace range replacement lines =
let
linesBefore : List String
linesBefore =
lines
|> List.take (range.start.row - 1)
linesAfter : List String
linesAfter =
lines
|> List.drop range.end.row
startLine : String
startLine =
getRowAtLine lines (range.start.row - 1)
startLineBefore : String
startLineBefore =
String.slice 0 (range.start.column - 1) startLine
endLine : String
endLine =
getRowAtLine lines (range.end.row - 1)
endLineAfter : String
endLineAfter =
String.dropLeft (range.end.column - 1) endLine
in
List.concat
[ linesBefore
, startLineBefore ++ replacement ++ endLineAfter |> String.lines
, linesAfter
]
getRowAtLine : List String -> Int -> String
getRowAtLine lines rowIndex =
case lines |> Array.fromList |> Array.get rowIndex of
Just line ->
if String.trim line /= "" then
line
else
""
Nothing ->
""
-- UTILITARIES FOR WORKING WITH RANGES
@ -144,134 +225,3 @@ mergeRanges a b =
a.end
in
{ start = start, end = end }
comparePosition : { row : Int, column : Int } -> { row : Int, column : Int } -> Order
comparePosition a b =
let
order : Order
order =
compare a.row b.row
in
case order of
EQ ->
compare a.column b.column
_ ->
order
applyFix : Fix -> String -> String
applyFix fix_ source =
source
|> (case fix_ of
Replacement range replacement ->
applyReplace range replacement
Removal range ->
applyReplace range ""
InsertAt position insertion ->
applyReplace { start = position, end = position } insertion
)
applyReplace : Range -> String -> String -> String
applyReplace range replacement source =
if range.start.row == range.end.row then
applySingleLineReplace
range
replacement
source
else
applyMultiLineReplace
range
replacement
source
applySingleLineReplace : Range -> String -> String -> String
applySingleLineReplace range replacement source =
let
lines : List String
lines =
String.lines source
linesBefore : String
linesBefore =
lines
|> List.take (range.start.row - 1)
|> String.join "\n"
linesAfter : String
linesAfter =
lines
|> List.drop range.end.row
|> String.join "\n"
line : String
line =
getRowAtLine lines (range.start.row - 1)
lineBefore : String
lineBefore =
String.slice 0 (range.start.column - 1) line
lineAfter : String
lineAfter =
String.dropLeft (range.end.column - 1) line
in
linesBefore ++ "\n" ++ lineBefore ++ replacement ++ lineAfter ++ "\n" ++ linesAfter
applyMultiLineReplace : Range -> String -> String -> String
applyMultiLineReplace range replacement source =
let
lines : List String
lines =
String.lines source
linesBefore : String
linesBefore =
lines
|> List.take (range.start.row - 1)
|> String.join "\n"
linesAfter : String
linesAfter =
lines
|> List.drop range.end.row
|> String.join "\n"
startLine : String
startLine =
getRowAtLine lines (range.start.row - 1)
startLineBefore : String
startLineBefore =
String.slice 0 (range.start.column - 1) startLine
endLine : String
endLine =
getRowAtLine lines (range.end.row - 1)
endLineAfter : String
endLineAfter =
String.dropLeft (range.end.column - 1) endLine
in
linesBefore ++ "\n" ++ startLineBefore ++ replacement ++ endLineAfter ++ "\n" ++ linesAfter
getRowAtLine : List String -> Int -> String
getRowAtLine lines rowIndex =
case lines |> Array.fromList |> Array.get rowIndex of
Just line ->
if String.trim line /= "" then
line
else
""
Nothing ->
""