diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,5 +1,8 @@
-# pcre-heavy [![Hackage](https://img.shields.io/hackage/v/pcre-heavy.svg?style=flat)](https://hackage.haskell.org/package/pcre-heavy) [![Build Status](https://img.shields.io/travis/myfreeweb/pcre-heavy.svg?style=flat)](https://travis-ci.org/myfreeweb/pcre-heavy) [![unlicense](https://img.shields.io/badge/un-license-green.svg?style=flat)](http://unlicense.org)
+[![Hackage](https://img.shields.io/hackage/v/pcre-heavy.svg?style=flat)](https://hackage.haskell.org/package/pcre-heavy)
+[![unlicense](https://img.shields.io/badge/un-license-green.svg?style=flat)](https://unlicense.org)
 
+# pcre-heavy
+
 *Finally!* A Haskell regular expressions library that does not suck.
 
 - based on [pcre-light], none of that regex-base complicated pluggable-backend stuff
@@ -22,14 +25,14 @@
 ### Checking
 
 ```haskell
->>> "https://unrelenting.technology" =~ [re|^http.*|]
+>>> "https://val.packett.cool" =~ [re|^http.*|]
 True
 ```
 
 For `UnicodeSyntax` fans, it's also available as ≈ (U+2248 ALMOST EQUAL TO):
 
 ```haskell
->>> "https://unrelenting.technology" ≈ [re|^http.*|]
+>>> "https://val.packett.cool" ≈ [re|^http.*|]
 True
 ```
 
@@ -118,11 +121,10 @@
 ## Contributing
 
 Please feel free to submit pull requests!
-Bugfixes and simple non-breaking improvements will be accepted without any questions :-)
 
-By participating in this project you agree to follow the [Contributor Code of Conduct](http://contributor-covenant.org/version/1/2/0/).
+By participating in this project you agree to follow the [Contributor Code of Conduct](http://contributor-covenant.org/version/1/4/).
 
 ## License
 
 This is free and unencumbered software released into the public domain.  
-For more information, please refer to the `UNLICENSE` file or [unlicense.org](http://unlicense.org).
+For more information, please refer to the `UNLICENSE` file or [unlicense.org](https://unlicense.org).
diff --git a/library/Text/Regex/PCRE/Heavy.hs b/library/Text/Regex/PCRE/Heavy.hs
--- a/library/Text/Regex/PCRE/Heavy.hs
+++ b/library/Text/Regex/PCRE/Heavy.hs
@@ -1,6 +1,7 @@
 {-# OPTIONS_GHC -fno-warn-orphans -fno-warn-unused-binds #-}
 {-# LANGUAGE NoImplicitPrelude, UndecidableInstances, FlexibleInstances, FlexibleContexts, BangPatterns #-}
 {-# LANGUAGE TemplateHaskell, QuasiQuotes, UnicodeSyntax #-}
+{-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE ForeignFunctionInterface, CPP #-}
 #if __GLASGOW_HASKELL__ < 710
 {-# LANGUAGE OverlappingInstances #-}
@@ -16,6 +17,7 @@
 , scanRanges
 , scanRangesO
   -- * Replacement
+, RegexReplacement
 , sub
 , subO
 , gsub
@@ -26,6 +28,8 @@
   -- * QuasiQuoter
 , re
 , mkRegexQQ
+  -- * Building regexes
+, escape
   -- * Types and stuff from pcre-light
 , Regex
 , PCREOption
@@ -51,22 +55,25 @@
 import           System.IO.Unsafe (unsafePerformIO)
 import           Foreign (withForeignPtr, allocaBytes, nullPtr, plusPtr, peekElemOff)
 
+-- $
+-- >>> :set -XQuasiQuotes -XFlexibleContexts -XOverloadedStrings
+-- >>> :m + Text.Regex.PCRE.Heavy
+-- >>> import qualified Text.Regex.PCRE.Light as PCRE
+
 substr ∷ SBS → (Int, Int) → SBS
 substr s (f, t) = BS.take (t - f) . BS.drop f $ s
 
 behead ∷ NE.NonEmpty a → (a, [a])
 behead l = (NE.head l, NE.tail l)
 
-reMatch ∷ (ConvertibleStrings SBS a, ConvertibleStrings a SBS) ⇒ Regex → a → Bool
+reMatch ∷ ConvertibleStrings a SBS ⇒ Regex → a → Bool
 reMatch r s = isJust $ PCRE.match r (cs s) []
 
 -- | Checks whether a string matches a regex.
 --
--- >>> :set -XQuasiQuotes
--- >>> :set -XFlexibleContexts
--- >>> "https://unrelenting.technology" =~ [re|^http.*|]
+-- >>> "https://val.packett.cool" =~ [re|^http.*|]
 -- True
-(=~), (≈) ∷ (ConvertibleStrings SBS a, ConvertibleStrings a SBS) ⇒ a → Regex → Bool
+(=~), (≈) ∷ ConvertibleStrings a SBS ⇒ a → Regex → Bool
 (=~) = flip reMatch
 
 -- | Same as =~.
@@ -74,7 +81,6 @@
 
 -- | Does raw PCRE matching (you probably shouldn't use this directly).
 --
--- >>> :set -XOverloadedStrings
 -- >>> rawMatch [re|\w{2}|] "a a ab abc ba" 0 []
 -- Just [(4,6)]
 -- >>> rawMatch [re|\w{2}|] "a a ab abc ba" 6 []
@@ -131,26 +137,32 @@
 -- [((0,17),[(7,8),(9,14)]),((17,27),[(23,24),(25,27)])]
 --
 -- And just like 'scan', it's lazy.
-scanRanges ∷ (ConvertibleStrings SBS a, ConvertibleStrings a SBS) ⇒ Regex → a → [((Int, Int), [(Int, Int)])]
+scanRanges ∷ ConvertibleStrings a SBS ⇒ Regex → a → [((Int, Int), [(Int, Int)])]
 scanRanges r s = scanRangesO r [] s
 
 -- | Exactly like 'scanRanges', but passes runtime options to PCRE.
-scanRangesO ∷ (ConvertibleStrings SBS a, ConvertibleStrings a SBS) ⇒ Regex → [PCREExecOption] → a → [((Int, Int), [(Int, Int)])]
+scanRangesO ∷ ConvertibleStrings a SBS ⇒ Regex → [PCREExecOption] → a → [((Int, Int), [(Int, Int)])]
 scanRangesO r opts s = map behead $ unfoldr (nextMatch r opts str) 0
   where str = toSBS s
 
+-- | Class of types that can serve as the replacement argument in the
+-- 'sub' family of functions.
 class RegexReplacement a where
   performReplacement ∷ SBS → [SBS] → a → SBS
 
+-- | A replacement string.
 instance {-# OVERLAPPABLE #-} ConvertibleStrings a SBS ⇒ RegexReplacement a where
   performReplacement _ _ to = cs to
 
+-- | A function mapping the matched string and groups to a replacement string.
 instance (ConvertibleStrings SBS a, ConvertibleStrings a SBS) ⇒ RegexReplacement (a → [a] → a) where
   performReplacement from groups replacer = cs $ replacer (cs from) (map cs groups)
 
+-- | A function mapping the matched string to a replacement string.
 instance (ConvertibleStrings SBS a, ConvertibleStrings a SBS) ⇒ RegexReplacement (a → a) where
   performReplacement from _ replacer = cs $ replacer (cs from)
 
+-- | A function mapping the matched groups to a replacement string.
 instance (ConvertibleStrings SBS a, ConvertibleStrings a SBS) ⇒ RegexReplacement ([a] → a) where
   performReplacement _ groups replacer = cs $ replacer (map cs groups)
 
@@ -199,7 +211,7 @@
 -- >>> gsub [re||] "" "Hello, world" :: String
 -- "Hello, world"
 --
--- https://github.com/myfreeweb/pcre-heavy/issues/2
+-- https://codeberg.org/valpackett/pcre-heavy/issues/2
 -- >>> gsub [re|good|] "bad" "goodgoodgood" :: String
 -- "badbadbad"
 --
@@ -248,7 +260,7 @@
 
 instance Lift PCREOption where
   -- well, the constructor isn't exported, but at least it implements Read/Show :D
-  lift o = let o' = show o in [| read o' ∷ PCREOption |]
+  liftTyped o = let o' = show o in [|| read o' ∷ PCREOption ||]
 
 quoteExpRegex ∷ [PCREOption] → String → ExpQ
 quoteExpRegex opts txt = [| PCRE.compile (cs (txt ∷ String)) opts |]
@@ -265,3 +277,31 @@
 -- | A QuasiQuoter for regular expressions that does a compile time check.
 re ∷ QuasiQuoter
 re = mkRegexQQ [utf8]
+
+-- Metacharacters used in PCRE syntax.  Taken from pcrepattern(3) man
+-- page.
+pcreMetachars ∷ SBS
+pcreMetachars = "\\^$.[|()?*+{"
+
+-- Start and end quote markers in PCRE syntax.
+startQuoteMarker, endQuoteMarker ∷ SBS
+startQuoteMarker = "\\Q"
+endQuoteMarker = "\\E"
+
+-- | Escapes the regex metacharacters in a string.  In other words,
+-- given a string, produces a regex that matches just that string (or
+-- case variations of that string, if case-insenstive matching is
+-- enabled).
+--
+-- >>> ("foo*bar"::String) =~ PCRE.compile (escape "foo*bar") []
+-- True
+escape ∷ (ConvertibleStrings a SBS, ConvertibleStrings SBS a) ⇒ a → a
+escape = convertString . escapeSBS . convertString
+  where escapeSBS s
+            -- Handle the special case where \Q...\E doesn't work.
+            | endQuoteMarker `BS.isInfixOf` s = BS.concatMap step s
+            -- Handle the typical case.
+            | otherwise = BS.concat [startQuoteMarker, s, endQuoteMarker]
+        step c
+            | c `BS.elem` pcreMetachars = BS.pack ['\\', c]
+            | otherwise = BS.singleton c
diff --git a/pcre-heavy.cabal b/pcre-heavy.cabal
--- a/pcre-heavy.cabal
+++ b/pcre-heavy.cabal
@@ -1,6 +1,6 @@
 name:            pcre-heavy
-version:         1.0.0.2
-synopsis:        A regexp library on top of pcre-light you can actually use.
+version:         1.0.0.3
+synopsis:        A regexp (regex) library on top of pcre-light you can actually use.
 description:
     A regular expressions library that does not suck.
 
@@ -12,10 +12,11 @@
 
     SEARCHES FOR MULTIPLE MATCHES! DOES REPLACEMENT!
 category:        Web
-homepage:        https://github.com/myfreeweb/pcre-heavy
-author:          Greg V
-copyright:       2015 Greg V <greg@unrelenting.technology>
-maintainer:      greg@unrelenting.technology
+homepage:        https://codeberg.org/valpackett/pcre-heavy
+bug-reports:     https://codeberg.org/valpackett/pcre-heavy/issues
+author:          Val Packett
+copyright:       2015-2022 Val Packett <val@packett.cool>
+maintainer:      val@packett.cool
 license:         PublicDomain
 license-file:    UNLICENSE
 build-type:      Simple
@@ -23,11 +24,11 @@
 extra-source-files:
     README.md
 tested-with:
-    GHC == 7.10.2
+    GHC == 8.0.1
 
 source-repository head
     type: git
-    location: git://github.com/myfreeweb/pcre-heavy.git
+    location: https://codeberg.org/valpackett/pcre-heavy.git
 
 library
     build-depends:
@@ -37,7 +38,7 @@
       , bytestring
       , string-conversions
       , semigroups
-      , template-haskell
+      , template-haskell >= 2.16.0.0
     default-language: Haskell2010
     exposed-modules:
         Text.Regex.PCRE.Heavy
