diff --git a/Cargo.lock b/Cargo.lock
index 3f6c5e12ba..f1958ad67b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1267,9 +1267,9 @@ dependencies = [
 
 [[package]]
 name = "pulldown-cmark"
-version = "0.7.2"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca36dea94d187597e104a5c8e4b07576a8a45aa5db48a65e12940d3eb7461f55"
+checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8"
 dependencies = [
  "bitflags",
  "getopts",
diff --git a/Cargo.toml b/Cargo.toml
index dd0b17bdf7..46fc04fac7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -25,7 +25,7 @@ lazy_static = "1.0"
 log = "0.4"
 memchr = "2.0"
 opener = "0.5"
-pulldown-cmark = "0.7.0"
+pulldown-cmark = "0.8.0"
 regex = "1.0.0"
 serde = "1.0"
 serde_derive = "1.0"
diff --git a/src/renderer/html_handlebars/search.rs b/src/renderer/html_handlebars/search.rs
index 5d9a5dc986..2dc717fb52 100644
--- a/src/renderer/html_handlebars/search.rs
+++ b/src/renderer/html_handlebars/search.rs
@@ -85,7 +85,7 @@ fn render_item(
         .with_context(|| "Could not convert HTML path to str")?;
     let anchor_base = utils::fs::normalize_path(filepath);
 
-    let mut p = utils::new_cmark_parser(&chapter.content).peekable();
+    let mut p = utils::new_cmark_parser(&chapter.content, false).peekable();
 
     let mut in_heading = false;
     let max_section_depth = u32::from(search_config.heading_split_level);
diff --git a/src/utils/mod.rs b/src/utils/mod.rs
index 2352517a13..31679ceb44 100644
--- a/src/utils/mod.rs
+++ b/src/utils/mod.rs
@@ -168,63 +168,29 @@ pub fn render_markdown(text: &str, curly_quotes: bool) -> String {
     render_markdown_with_path(text, curly_quotes, None)
 }
 
-pub fn new_cmark_parser(text: &str) -> Parser<'_> {
+pub fn new_cmark_parser(text: &str, curly_quotes: bool) -> Parser<'_> {
     let mut opts = Options::empty();
     opts.insert(Options::ENABLE_TABLES);
     opts.insert(Options::ENABLE_FOOTNOTES);
     opts.insert(Options::ENABLE_STRIKETHROUGH);
     opts.insert(Options::ENABLE_TASKLISTS);
+    if curly_quotes {
+        opts.insert(Options::ENABLE_SMART_PUNCTUATION);
+    }
     Parser::new_ext(text, opts)
 }
 
 pub fn render_markdown_with_path(text: &str, curly_quotes: bool, path: Option<&Path>) -> String {
     let mut s = String::with_capacity(text.len() * 3 / 2);
-    let p = new_cmark_parser(text);
-    let mut converter = EventQuoteConverter::new(curly_quotes);
+    let p = new_cmark_parser(text, curly_quotes);
     let events = p
         .map(clean_codeblock_headers)
-        .map(|event| adjust_links(event, path))
-        .map(|event| converter.convert(event));
+        .map(|event| adjust_links(event, path));
 
     html::push_html(&mut s, events);
     s
 }
 
-struct EventQuoteConverter {
-    enabled: bool,
-    convert_text: bool,
-}
-
-impl EventQuoteConverter {
-    fn new(enabled: bool) -> Self {
-        EventQuoteConverter {
-            enabled,
-            convert_text: true,
-        }
-    }
-
-    fn convert<'a>(&mut self, event: Event<'a>) -> Event<'a> {
-        if !self.enabled {
-            return event;
-        }
-
-        match event {
-            Event::Start(Tag::CodeBlock(_)) => {
-                self.convert_text = false;
-                event
-            }
-            Event::End(Tag::CodeBlock(_)) => {
-                self.convert_text = true;
-                event
-            }
-            Event::Text(ref text) if self.convert_text => {
-                Event::Text(CowStr::from(convert_quotes_to_curly(text)))
-            }
-            _ => event,
-        }
-    }
-}
-
 fn clean_codeblock_headers(event: Event<'_>) -> Event<'_> {
     match event {
         Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(ref info))) => {
@@ -243,38 +209,6 @@ fn clean_codeblock_headers(event: Event<'_>) -> Event<'_> {
     }
 }
 
-fn convert_quotes_to_curly(original_text: &str) -> String {
-    // We'll consider the start to be "whitespace".
-    let mut preceded_by_whitespace = true;
-
-    original_text
-        .chars()
-        .map(|original_char| {
-            let converted_char = match original_char {
-                '\'' => {
-                    if preceded_by_whitespace {
-                        '‘'
-                    } else {
-                        '’'
-                    }
-                }
-                '"' => {
-                    if preceded_by_whitespace {
-                        '“'
-                    } else {
-                        '”'
-                    }
-                }
-                _ => original_char,
-            };
-
-            preceded_by_whitespace = original_char.is_whitespace();
-
-            converted_char
-        })
-        .collect()
-}
-
 /// Prints a "backtrace" of some `Error`.
 pub fn log_backtrace(e: &Error) {
     error!("Error: {}", e);
@@ -450,23 +384,4 @@ more text with spaces
             assert_eq!(normalize_id(""), "");
         }
     }
-
-    mod convert_quotes_to_curly {
-        use super::super::convert_quotes_to_curly;
-
-        #[test]
-        fn it_converts_single_quotes() {
-            assert_eq!(convert_quotes_to_curly("'one', 'two'"), "‘one’, ‘two’");
-        }
-
-        #[test]
-        fn it_converts_double_quotes() {
-            assert_eq!(convert_quotes_to_curly(r#""one", "two""#), "“one”, “two”");
-        }
-
-        #[test]
-        fn it_treats_tab_as_whitespace() {
-            assert_eq!(convert_quotes_to_curly("\t'one'"), "\t‘one’");
-        }
-    }
 }