diff --git a/CHANGELOG b/CHANGELOG
deleted file mode 100644
--- a/CHANGELOG
+++ /dev/null
@@ -1,116 +0,0 @@
-
-0.11
-----
-
-API changes:
- * Added `gotoBOF`, `gotoEOF`, `killToBOF`, and `killToEOF` functions
-   (thanks Itai Y. Efrat)
-
-0.10.1
-------
-
- * WordSpec: fix a test verification bug (fixed #11)
- * WordSpec: generation of random text should never include newlines
-
-0.10
-----
-
-- Integrated word editing and navigation functions
-  courtesy of Hans-Peter Deifel's hledger-iadd project (see
-  Data.Text.Zipper.Generic.Words)
-- Added currentChar, nextChar, and previousChar (thanks @kRITZCREEK)
-
-0.9
----
-
-- insertChar and insertMany now only insert printable characters and
-  newlines (subject to text zipper line limits)
-- The GenericTextZipper class now requires a new method,
-  toList :: a -> [Char]
-
-0.8.3
------
-
-- Fixed insertMany accidental addition of trailing newline
-
-0.8.2
------
-
-- Fixed insertMany for zippers with no line limit
-
-0.8.1
------
-
-- Added Github links and CHANGELOG to package
-
-0.8
----
-
-- Added 'transposeChars' function
-
-0.7.1
------
-
-- Generic: import everything from Monoid for older GHCs
-
-0.7
----
-
-- API changes: Add Generic module to abstract over text container types
-
-0.6.1
------
-
-- Make insertMany respect the zipper's line limit
-
-0.6
----
-
-- Add insertMany for faster bulk insertion
-
-0.5
----
-
-- Added killToBOL function (thanks Hans-Peter Deifel)
-- Enabled -Wall
-- Added dependency on deepseq
-- Added NFData instance for TextZipper
-
-0.4
----
-
-- Added clearZipper
-- Added isFirstLine (thanks Kwang Yul Seo)
-- Renamed lastLine to isLastLine (thanks Kwang Yul Seo)
-
-0.3.1
------
-
-- Fixed export of vectorZipper
-
-0.3
----
-
-- Added vectorZipper for zipping over vectors of characters
-
-0.2.1
------
-
-- Exported getLineLimit to permit obtaining a zipper's line limit
-
-0.2
----
-
-- Added support for limiting the number of lines in the zipper
-- insertChar "\n" is now equivalent to breakLine
-- Improved Show instance for TextZipper
-
-0.1.1
------
-
-- Updated package metadata
-
-0.1
----
-
-Initial release (originally split off from vty-ui)
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,123 @@
+
+0.12
+----
+
+API changes:
+ * Added `moveCursorClosest` to allow cursor placement as near as
+   possible to a specified location.
+
+0.11
+----
+
+API changes:
+ * Added `gotoBOF`, `gotoEOF`, `killToBOF`, and `killToEOF` functions
+   (thanks Itai Y. Efrat)
+
+0.10.1
+------
+
+ * WordSpec: fix a test verification bug (fixed #11)
+ * WordSpec: generation of random text should never include newlines
+
+0.10
+----
+
+- Integrated word editing and navigation functions
+  courtesy of Hans-Peter Deifel's hledger-iadd project (see
+  Data.Text.Zipper.Generic.Words)
+- Added currentChar, nextChar, and previousChar (thanks @kRITZCREEK)
+
+0.9
+---
+
+- insertChar and insertMany now only insert printable characters and
+  newlines (subject to text zipper line limits)
+- The GenericTextZipper class now requires a new method,
+  toList :: a -> [Char]
+
+0.8.3
+-----
+
+- Fixed insertMany accidental addition of trailing newline
+
+0.8.2
+-----
+
+- Fixed insertMany for zippers with no line limit
+
+0.8.1
+-----
+
+- Added Github links and CHANGELOG to package
+
+0.8
+---
+
+- Added 'transposeChars' function
+
+0.7.1
+-----
+
+- Generic: import everything from Monoid for older GHCs
+
+0.7
+---
+
+- API changes: Add Generic module to abstract over text container types
+
+0.6.1
+-----
+
+- Make insertMany respect the zipper's line limit
+
+0.6
+---
+
+- Add insertMany for faster bulk insertion
+
+0.5
+---
+
+- Added killToBOL function (thanks Hans-Peter Deifel)
+- Enabled -Wall
+- Added dependency on deepseq
+- Added NFData instance for TextZipper
+
+0.4
+---
+
+- Added clearZipper
+- Added isFirstLine (thanks Kwang Yul Seo)
+- Renamed lastLine to isLastLine (thanks Kwang Yul Seo)
+
+0.3.1
+-----
+
+- Fixed export of vectorZipper
+
+0.3
+---
+
+- Added vectorZipper for zipping over vectors of characters
+
+0.2.1
+-----
+
+- Exported getLineLimit to permit obtaining a zipper's line limit
+
+0.2
+---
+
+- Added support for limiting the number of lines in the zipper
+- insertChar "\n" is now equivalent to breakLine
+- Improved Show instance for TextZipper
+
+0.1.1
+-----
+
+- Updated package metadata
+
+0.1
+---
+
+Initial release (originally split off from vty-ui)
diff --git a/src/Data/Text/Zipper.hs b/src/Data/Text/Zipper.hs
--- a/src/Data/Text/Zipper.hs
+++ b/src/Data/Text/Zipper.hs
@@ -27,6 +27,7 @@
 
     -- * Navigation functions
     , moveCursor
+    , moveCursorClosest
     , moveRight
     , moveLeft
     , moveUp
@@ -184,6 +185,22 @@
                , toLeft = take_ tz col (t !! row)
                , toRight = drop_ tz col (t !! row)
                }
+
+-- | Move the cursor to the specified row and column. Invalid cursor
+-- positions will be reinterpreted as the closest valid position. Valid
+-- cursor positions range as described for 'cursorPosition'.
+moveCursorClosest :: (Monoid a) => (Int, Int) -> TextZipper a -> TextZipper a
+moveCursorClosest (row, col) tz =
+    let t = getText tz
+        bestRow = min (max 0 $ length t - 1) $ max 0 row
+        bestCol = if bestRow < length t
+                  then min (length_ tz (t !! bestRow)) $ max 0 col
+                  else 0
+    in tz { above = take bestRow t
+          , below = drop (bestRow + 1) t
+          , toLeft = take_ tz bestCol (t !! bestRow)
+          , toRight = drop_ tz bestCol (t !! bestRow)
+          }
 
 isFirstLine :: TextZipper a -> Bool
 isFirstLine = null . above
diff --git a/text-zipper.cabal b/text-zipper.cabal
--- a/text-zipper.cabal
+++ b/text-zipper.cabal
@@ -1,5 +1,5 @@
 name:                text-zipper
-version:             0.11
+version:             0.12
 synopsis:            A text editor zipper library
 description:         This library provides a zipper and API for editing text.
 license:             BSD3
@@ -10,7 +10,7 @@
 category:            Text
 build-type:          Simple
 cabal-version:       >=1.10
-data-files:          CHANGELOG
+data-files:          CHANGELOG.md
 homepage:            https://github.com/jtdaugherty/text-zipper/
 bug-reports:         https://github.com/jtdaugherty/text-zipper/issues
 
