diff --git a/fix-imports.cabal b/fix-imports.cabal
--- a/fix-imports.cabal
+++ b/fix-imports.cabal
@@ -1,5 +1,5 @@
 name: fix-imports
-version: 0.1.1
+version: 0.1.2
 cabal-version: >= 1.6
 build-type: Simple
 synopsis: Program to manage the imports of a haskell module
diff --git a/src/FixImports.hs b/src/FixImports.hs
--- a/src/FixImports.hs
+++ b/src/FixImports.hs
@@ -34,9 +34,6 @@
         imports, and groups them by their toplevel module name (before the
         first dot).  Small groups are combined.  They go in alphabetical order
         by default, but a per-project order may be defined.
-
-    - If there are no imports to be added or removed, the file is returned
-    unchanged.  This means it won't sort the imports in this case.
 -}
 module FixImports where
 import Prelude hiding (mod)
@@ -44,18 +41,18 @@
 import qualified Control.Monad as Monad
 import qualified Data.Either as Either
 import qualified Data.Generics.Uniplate.Data as Uniplate
+import qualified Data.List as List
 import qualified Data.Map as Map
 import qualified Data.Maybe as Maybe
 import qualified Data.Set as Set
 
-import qualified Language.Preprocessor.Cpphs as Cpphs
 import qualified Language.Haskell.Exts.Annotated as Haskell
-
+import qualified Language.Preprocessor.Cpphs as Cpphs
 import qualified System.Directory as Directory
 import qualified System.Environment
 import qualified System.Exit
 import qualified System.FilePath as FilePath
-import System.FilePath ( (</>) )
+import System.FilePath ((</>))
 import qualified System.IO as IO
 import qualified System.Process as Process
 
@@ -150,39 +147,35 @@
         , Cpphs.warnings = False
         }
 
--- | Take a parsed module along with its unparsed text.  If the imports should
--- change, generate a new import block with proper spacing, formatting, and
--- comments.  Then snip out the import block on the import file, and replace
--- it.  Otherwise, the unparsed input module is returned unchanged.
+-- | Take a parsed module along with its unparsed text.  Generate a new import
+-- block with proper spacing, formatting, and comments.  Then snip out the
+-- import block on the import file, and replace it.
 fixImports :: Config.Config -> FilePath -> Types.Module -> [Haskell.Comment]
     -> String -> IO (Either String Result)
-fixImports config modulePath mod cmts text
-    | Set.null newImports && Set.null unusedImports =
-        return $ Right $ Result text Set.empty Set.empty
-    | otherwise = do
-        -- Don't bother loading the index if I'm not going to use it.
-        -- TODO actually, only load it if I don't find local imports
-        -- I guess Data.Binary's laziness will serve me there
-        index <- if Set.null newImports
-            then return Index.empty
-            else Index.loadIndex (Config.configIndex config)
-        mbNew <- mapM (mkImportLine modulePath index) (Set.toList newImports)
-        mbExisting <- mapM findImport imports
-        let existing = map (Types.importDeclModule . fst) imports
-        let (notFound, importLines) = Either.partitionEithers $
-                zipWith mkError
-                    (map toModule (Set.toList newImports) ++ existing)
-                    (mbNew ++ mbExisting)
-            mkError _ (Just imp) = Right imp
-            mkError mod Nothing = Left mod
-        return $ case notFound of
-            _ : _ -> Left $ "modules not found: "
-                ++ Util.join ", " (map Types.moduleName notFound)
-            [] -> Right $ Result
-                (substituteImports (showImports importLines) range text)
-                (Set.fromList (map (Types.importDeclModule . Types.importDecl)
-                    (Maybe.catMaybes mbNew)))
-                unusedImports
+fixImports config modulePath mod cmts text = do
+    -- Don't bother loading the index if I'm not going to use it.
+    -- TODO actually, only load it if I don't find local imports
+    -- I guess Data.Binary's laziness will serve me there
+    index <- if Set.null newImports
+        then return Index.empty
+        else Index.loadIndex (Config.configIndex config)
+    mbNew <- mapM (mkImportLine modulePath index) (Set.toList newImports)
+    mbExisting <- mapM findImport imports
+    let existing = map (Types.importDeclModule . fst) imports
+    let (notFound, importLines) = Either.partitionEithers $
+            zipWith mkError
+                (map toModule (Set.toList newImports) ++ existing)
+                (mbNew ++ mbExisting)
+        mkError _ (Just imp) = Right imp
+        mkError mod Nothing = Left mod
+    return $ case notFound of
+        _ : _ -> Left $ "modules not found: "
+            ++ Util.join ", " (map Types.moduleName notFound)
+        [] -> Right $ Result
+            (substituteImports (showImports importLines) range text)
+            (Set.fromList (map (Types.importDeclModule . Types.importDecl)
+                (Maybe.catMaybes mbNew)))
+            unusedImports
     where
     (newImports, unusedImports, imports, range) = importInfo mod cmts
     toModule (Types.Qualification name) = Types.ModuleName name
@@ -321,30 +314,31 @@
 
 
 -- | Pair ImportDecls up with the comments that apply to them.  Comments
--- below the last import are dropped.  Comments that are separated from an
--- import by a blank line will also be lost.  It could be fixed but I don't
--- think I write those comments.
+-- below the last import are dropped, but there shouldn't be any of those
+-- because they should have been omitted from the comment block.
 --
--- Also misses cmts that have leading whitespace.  Don't do that.
--- To do it right I'd have to sort imports and cmts and pull cmts off with
--- a foldl.
+-- Spaces between comments above an import will be lost, and multiple comments
+-- to the right of an import (e.g. commenting a complicated import list) will
+-- probably be messed up.  TODO Fix it if it becomes a problem.
 associateComments :: [Types.ImportDecl] -> [Haskell.Comment]
     -> [(Types.ImportDecl, [Types.Comment])]
-associateComments imports cmts = [(imp, cmtsFor imp) | imp <- imports]
+associateComments imports cmts = snd $ List.mapAccumL associate cmts imports
     where
-    cmtsFor imp = Util.mapMaybe (associate src) cmts
-        where src = Haskell.srcInfoSpan (Haskell.importAnn imp)
-    associate src (Haskell.Comment block csrc text)
-        | start csrc == end csrc && start csrc `within` src =
-            Just $ Types.Comment Types.CmtRight cmt
-        | Haskell.srcSpanStartColumn csrc == 1 && end csrc + 1 == start src =
-            Just $ Types.Comment Types.CmtAbove cmt
-        | otherwise = Nothing
+    associate cmts imp = (after, (imp, associated))
         where
-        cmt = if block then "{-" ++ text ++ "-}" else "--" ++ text
+        associated = map (Types.Comment Types.CmtAbove . cmtText) above
+            ++ map (Types.Comment Types.CmtRight . cmtText) right
+        -- cmts that end before the import beginning are above it
+        (above, rest) = List.span ((< start impSpan) . end . cmtSpan) cmts
+        -- remaining cmts that start before or at the import's end are right
+        -- of it
+        (right, after) = List.span ((<= end impSpan) . start . cmtSpan) rest
+        impSpan = Haskell.srcInfoSpan (Haskell.importAnn imp)
+    cmtSpan (Haskell.Comment _ span _) = span
+    cmtText (Haskell.Comment True _ s) = "{-" ++ s ++ "-}"
+    cmtText (Haskell.Comment False _ s) = "--" ++ s
     start = Haskell.srcSpanStartLine
     end = Haskell.srcSpanEndLine
-    within line src = line >= start src && line <= end src
 
 parse :: String -> (Types.Module -> [Haskell.Comment] -> a) -> Either String a
 parse text f = case Haskell.parseFileContentsWithComments mode text of
@@ -377,9 +371,9 @@
     | Haskell.Qual _ m _ <- Uniplate.universeBi mod]
 
 
-{-
 -- * test
 
+{-
 test = do
     res <- fixModule (Config.defaultConfig ["base"])  "TestMod.hs" tmod
     case res of
@@ -403,6 +397,7 @@
 \) where\n\
 \import qualified Data.List as C\n\
 \-- I want this comment\n\
+\-- And this one\n\
 \import qualified Util -- cmt right\n\
 \import qualified Extra as Biz {- block cmt -}\n\
 \import Data.Map (a,\n\
diff --git a/vimrc b/vimrc
--- a/vimrc
+++ b/vimrc
@@ -15,21 +15,26 @@
     execute 'silent !FixImports -v' expand('%') '<' tmp '>' out '2>' err
     let errs = readfile(err)
     if v:shell_error == 0
-        " Is there an easier way to replace the buffer with a file?
-        let old_line = line('.')
-        let old_col = col('.')
-        let old_total = line('$')
-        %d
-        execute 'silent :read' out
-        0d
-        let new_total = line('$')
-        " If the import fix added or removed lines I need to take that into
-        " account.  This will be wrong if the cursor was above the import
-        " block.
-        call cursor(old_line + (new_total - old_total), old_col)
-        " The reload will forget fold state.  It was open, right?
-        if foldclosed('.') != -1
-            execute 'normal zO'
+        " Don't replace the buffer if there's no change, this way I won't
+        " mess up fold and undo state.
+        call system('cmp -s ' . tmp . ' ' . out)
+        if v:shell_error != 0
+            " Is there an easier way to replace the buffer with a file?
+            let old_line = line('.')
+            let old_col = col('.')
+            let old_total = line('$')
+            %d
+            execute 'silent :read' out
+            0d
+            let new_total = line('$')
+            " If the import fix added or removed lines I need to take that
+            " into account.  This will be wrong if the cursor was above the
+            " import block.
+            call cursor(old_line + (new_total - old_total), old_col)
+            " The reload will forget fold state.  It was open, right?
+            if foldclosed('.') != -1
+                execute 'normal zO'
+            endif
         endif
     endif
     call delete(out)
