mirror of
https://github.com/koalaman/shellcheck
synced 2025-07-15 01:23:07 -07:00
Move fix application logic to separate module
This commit is contained in:
parent
3471ad45b1
commit
bc111141f8
2 changed files with 75 additions and 77 deletions
67
src/ShellCheck/Fixer.hs
Normal file
67
src/ShellCheck/Fixer.hs
Normal file
|
@ -0,0 +1,67 @@
|
|||
module ShellCheck.Fixer (applyFix , replaceMultiLines) where
|
||||
|
||||
import ShellCheck.Interface
|
||||
|
||||
import Data.List
|
||||
|
||||
applyFix fix fileLines =
|
||||
-- apply replacements in sorted order by end position
|
||||
-- assert no overlaps, or maybe remove overlaps?
|
||||
let sorted = (reverse . sort) (fixReplacements fix) in
|
||||
applyReplacement sorted fileLines
|
||||
where
|
||||
applyReplacement [] s = s
|
||||
applyReplacement (rep:xs) s = applyReplacement xs $ replaceMultiLines rep s
|
||||
|
||||
-- A replacement that spans multiple line is applied by:
|
||||
-- 1. merging the affected lines into a single string using `unlines`
|
||||
-- 2. apply the replacement as if it only spanned a single line
|
||||
-- The tricky part is adjusting the end column of the replacement
|
||||
-- (the end line doesn't matter because there is only one line)
|
||||
--
|
||||
-- aaS <--- start of replacement (row 1 column 3)
|
||||
-- bbbb
|
||||
-- cEc
|
||||
-- \------- end of replacement (row 3 column 2)
|
||||
--
|
||||
-- a flattened string will look like:
|
||||
--
|
||||
-- "aaS\nbbbb\ncEc\n"
|
||||
--
|
||||
-- The column of E has to be adjusted by:
|
||||
-- 1. lengths of lines to be replaced, except the end row itself
|
||||
-- 2. end column of the replacement
|
||||
-- 3. number of '\n' by `unlines`
|
||||
-- Returns the original lines from the file with the replacement applied.
|
||||
-- Multiline replacements completely overwrite new lines in the original string.
|
||||
-- e.g. if the replacement spans 2 lines, but the replacement string does not
|
||||
-- have a '\n', then the number of replaced lines will be 1 shorter.
|
||||
replaceMultiLines rep fileLines = -- this can replace doReplace
|
||||
let startRow = fromIntegral $ (posLine . repStartPos) rep
|
||||
endRow = fromIntegral $ (posLine . repEndPos) rep
|
||||
(ys, zs) = splitAt endRow fileLines
|
||||
(xs, toReplaceLines) = splitAt (startRow-1) ys
|
||||
lengths = fromIntegral $ sum (map length (init toReplaceLines))
|
||||
newlines = fromIntegral $ (length toReplaceLines - 1) -- for the '\n' from unlines
|
||||
original = unlines toReplaceLines
|
||||
startCol = ((posColumn . repStartPos) rep)
|
||||
endCol = ((posColumn . repEndPos) rep + newlines + lengths)
|
||||
replacedLines = (lines $ doReplace startCol endCol original (repString rep))
|
||||
in
|
||||
xs ++ replacedLines ++ zs
|
||||
|
||||
-- FIXME: Work correctly with tabs
|
||||
-- start and end comes from pos, which is 1 based
|
||||
-- doReplace 0 0 "1234" "A" -> "A1234" -- technically not valid
|
||||
-- doReplace 1 1 "1234" "A" -> "A1234"
|
||||
-- doReplace 1 2 "1234" "A" -> "A234"
|
||||
-- doReplace 3 3 "1234" "A" -> "12A34"
|
||||
-- doReplace 4 4 "1234" "A" -> "123A4"
|
||||
-- doReplace 5 5 "1234" "A" -> "1234A"
|
||||
doReplace start end o r =
|
||||
let si = fromIntegral (start-1)
|
||||
ei = fromIntegral (end-1)
|
||||
(x, xs) = splitAt si o
|
||||
(y, z) = splitAt (ei - si) xs
|
||||
in
|
||||
x ++ r ++ z
|
Loading…
Add table
Add a link
Reference in a new issue