@@ -80,7 +80,7 @@ impl Input {
8080 pub fn id ( & self ) -> String {
8181 let title = & self . title ;
8282 // The ID is all lower-case
83- let mut title_with_replacements = String :: from ( title) . to_lowercase ( ) ;
83+ let mut title_with_replacements: String = String :: from ( title) . to_lowercase ( ) ;
8484
8585 // Replace characters that aren't allowed in the ID, usually with a dash or an empty string
8686 let substitutions = [
@@ -125,7 +125,7 @@ impl Input {
125125 ( "]" , "" ) ,
126126 // TODO: Curly braces shouldn't appear in the title in the first place.
127127 // They'd be interpreted as attributes there.
128- // Print an error in that case? Escape them with AciiDoc escapes?
128+ // Print an error in that case? Escape them with AsciiDoc escapes?
129129 ( "{" , "" ) ,
130130 ( "}" , "" ) ,
131131 ] ;
@@ -135,12 +135,24 @@ impl Input {
135135 title_with_replacements = title_with_replacements. replace ( old, new) ;
136136 }
137137
138- // Make sure the converted ID doesn't contain double dashes ("--"), because
138+ // Replace remaining characters that aren't ASCII, or that are non-alphanumeric ASCII,
139+ // with dashes. For example, this replaces diacritics and typographic quotation marks.
140+ title_with_replacements = title_with_replacements. chars ( )
141+ . map ( |c| if c. is_ascii_alphanumeric ( ) { c } else { '-' } )
142+ . collect ( ) ;
143+
144+ // Ensure the converted ID doesn't contain double dashes ("--"), because
139145 // that breaks references to the ID
140146 while title_with_replacements. contains ( "--" ) {
141147 title_with_replacements = title_with_replacements. replace ( "--" , "-" ) ;
142148 }
143149
150+ // Ensure that the ID doesn't end with a dash
151+ if title_with_replacements. ends_with ( "-" ) {
152+ let len = title_with_replacements. len ( ) ;
153+ title_with_replacements = title_with_replacements[ ..len-1 ] . to_string ( ) ;
154+ }
155+
144156 let prefix = self . prefix ( ) ;
145157
146158 format ! ( "{}{}" , prefix, title_with_replacements)
0 commit comments