diff --git a/README.md b/README.md index 870e92b..a423f56 100644 --- a/README.md +++ b/README.md @@ -250,7 +250,21 @@ If you want to do specialized formatting within a given string, Squib has lots o * Apostraphes are converted to curly as well. * LaTeX-style quotes are explicitly converted (``like this'') * Em-dash and en-dash are converted with triple and double-dashes respectively (-- is an en-dash, and --- becomes an em-dash.) -* Ellipses can be specified with .... Note that this is entirely different from the `ellipsize` option (which determines what to do with overflowing text). +* Ellipses can be specified with .... Note that this is entirely different from the `ellipsize` option, which is determining what to do with overflowing text. + +The above replacements assume you are using the UTF-8 character set. If you wish to change the characters, set the following configuration options in your `config.yml` + +```yaml + lsquote: "\u2018" #note that Yaml wants double quotes here to use escape chars + rsquote: "\u2019" + ldquote: "\u201C" + rdquote: "\u201D" + em_dash: "\u2014" + en_dash: "\u2013" + ellipsis: "\u2026" +``` + +You can also disable the auto-quoting mechanism by setting `smart_quotes: false` in your config. Explicit replacements will still be performed. ### Text Samples @@ -258,10 +272,18 @@ Examples of all of the above are crammed into the `text_options.rb` sample [foun {include:file:samples/text_options.rb} -Also, the `embed_text.rb` sample has more examples of embedding text, which can be [found here](https://github.com/andymeneely/squib/tree/master/samples/embed_text.rb). +The `embed_text.rb` sample has more examples of embedding text, which can be [found here](https://github.com/andymeneely/squib/tree/master/samples/embed_text.rb). {include:file:samples/embed_text.rb} +The `config_text_markup.rb` sample demonstrates how quoting can be configured, [found here](https://github.com/andymeneely/squib/tree/master/samples/config_text_markup.rb) + +{include:file:samples/config_text_markup.rb} + +{include:file:samples/config_text_markup.yml} + + + ## Custom Layouts Working with x-y coordinates all the time can be tiresome, and ideally everything in a game prototype should be data-driven and easily changed. For this, many Squib methods allow for a `layout` to be set. In essence, layouts are a way of setting default values for any argument given to the command. diff --git a/lib/squib/args/typographer.rb b/lib/squib/args/typographer.rb index 1ab62ab..ab753c8 100644 --- a/lib/squib/args/typographer.rb +++ b/lib/squib/args/typographer.rb @@ -8,17 +8,27 @@ module Squib end def process(str) - [ - :left_curly, - :right_curly, - :apostraphize, + str = explicit_replacements(str) + str = smart_quotes(str) if @config['smart_quotes'] + str + end + + def explicit_replacements(str) + [ :left_curly, :right_curly, :apostraphize, + :ellipsificate, :em_dash, :en_dash ].each do |sym| + str = each_non_tag(str) do |token| + self.method(sym).call(token) + end + end + str + end + + def smart_quotes(str) + [ :single_inside_double_quote, :right_double_quote, :left_double_quote, :right_single_quote, - :left_single_quote, - :ellipsificate, - :em_dash, - :en_dash ].each do |sym| + :left_single_quote].each do |sym| str = each_non_tag(str) do |token| self.method(sym).call(token) end @@ -43,52 +53,58 @@ module Squib # Straightforward replace def left_curly(str) - str.gsub('``', "\u201C") + str.gsub('``', @config['ldquote']) end # Straightforward replace def right_curly(str) - str.gsub(%{''}, "\u201D") + str.gsub(%{''}, @config['rdquote']) end # A quote between two letters is an apostraphe def apostraphize(str) - str.gsub(/(\w)(\')(\w)/, '\1' + "\u2019" + '\3') + str.gsub(/(\w)(\')(\w)/, '\1' + @config['rsquote'] + '\3') end - # Quote next to non-whitespace curls - def right_double_quote(str) - str.gsub(/(\S)(\")/, '\1' + "\u201D") + # Straightforward replace + def ellipsificate(str) + str.gsub('...', @config['ellipsis']) end - # Quote next to non-whitespace curls - def left_double_quote(str) - str.gsub(/(\")(\S)/, "\u201C" + '\2') + # Straightforward replace + def en_dash(str) + str.gsub('--', @config['en_dash']) + end + + # Straightforward replace + def em_dash(str) + str.gsub('---', @config['em_dash']) end # Quote next to non-whitespace curls - def right_single_quote(str) - str.gsub(/(\S)(\')/, '\1' + "\u2019") + def right_double_quote(str) + str.gsub(/(\S)(\")/, '\1' + @config['rdquote']) end # Quote next to non-whitespace curls - def left_single_quote(str) - str.gsub(/(\')(\S)/, "\u2018" + '\2') + def left_double_quote(str) + str.gsub(/(\")(\S)/, @config['ldquote'] + '\2') end - # Straightforward replace - def ellipsificate(str) - str.gsub('...', "\u2026") + # Handle the cases where a double quote is next to a single quote + def single_inside_double_quote(str) + str.gsub(/(\")(\')(\S)/, @config['ldquote'] + @config['lsquote'] + '\3') + .gsub(/(\")(\')(\S)/, '\1' + @config['rsquote'] + @config['rdquote']) end - # Straightforward replace - def en_dash(str) - str.gsub('--', "\u2013") + # Quote next to non-whitespace curls + def right_single_quote(str) + str.gsub(/(\S)(\')/, '\1' + @config['rsquote']) end - # Straightforward replace - def em_dash(str) - str.gsub('---', "\u2014") + # Quote next to non-whitespace curls + def left_single_quote(str) + str.gsub(/(\')(\S)/, @config['lsquote'] + '\2') end end diff --git a/lib/squib/constants.rb b/lib/squib/constants.rb index 7864d5a..9ed0dc4 100644 --- a/lib/squib/constants.rb +++ b/lib/squib/constants.rb @@ -80,6 +80,14 @@ module Squib 'hint' => :none, 'img_dir' => '.', 'progress_bar' => false, + 'ldquote' => "\u201C", # UTF8 chars + 'rdquote' => "\u201D", + 'lsquote' => "\u2018", + 'rsquote' => "\u2019", + 'em_dash' => "\u2014", + 'en_dash' => "\u2013", + 'ellipsis' => "\u2026", + 'smart_quotes' => true, } #Translate the hints to the methods. diff --git a/lib/squib/deck.rb b/lib/squib/deck.rb index f047d15..c63d2a2 100644 --- a/lib/squib/deck.rb +++ b/lib/squib/deck.rb @@ -34,7 +34,7 @@ module Squib # :nodoc: # @api private - attr_reader :layout, :config + attr_reader :layout, :config, :quote_chars attr_reader :dir, :prefix, :count_format @@ -70,6 +70,7 @@ module Squib @dir = SYSTEM_DEFAULTS[:dir] @prefix = SYSTEM_DEFAULTS[:prefix] @count_format = SYSTEM_DEFAULTS[:count_format] + @quote_chars = CONFIG_DEFAULTS.select {|k,v| %w(lsquote rsquote ldquote rdquote smart_quotes).include?(k) } show_info(config, layout) load_config(config) @width = Args::UnitConversion.parse width, dpi @@ -111,6 +112,10 @@ module Squib @prefix = config['prefix'] @count_format = config['count_format'] @antialias = config['antialias'] + @quote_chars ||= {} + %w(lsquote rsquote ldquote rdquote smart_quotes em_dash en_dash ellipsis).each do |key| + @quote_chars[key] = config[key] + end end end diff --git a/lib/squib/graphics/text.rb b/lib/squib/graphics/text.rb index 61951c6..89338af 100644 --- a/lib/squib/graphics/text.rb +++ b/lib/squib/graphics/text.rb @@ -156,7 +156,7 @@ module Squib layout.font_description = font_desc layout.text = str if markup - str = Args::Typographer.new(@deck.config).process(layout.text) + str = Args::Typographer.new(@deck.quote_chars).process(layout.text) layout.markup = str end diff --git a/lib/squib/project_template/config.yml b/lib/squib/project_template/config.yml index 6ffa218..4984020 100644 --- a/lib/squib/project_template/config.yml +++ b/lib/squib/project_template/config.yml @@ -25,3 +25,16 @@ # Use a SVG cairo back end, instead of an in-memory buffer # backend: :memory # default # backend: :svg # can create scalable pdfs, but rendering done at the printer level is not as good as Cairo. + +# Configure what text markup uses replace characters +# Below are the defaults +# lsquote: "\u2018" #note that Yaml wants double quotes here to use escape chars +# rsquote: "\u2019" +# ldquote: "\u201C" +# rdquote: "\u201D" +# em_dash: "\u2014" +# en_dash: "\u2013" +# ellipsis: "\u2026" + +# We can also disallow smart quotes and only allow explicit replacements with ``LaTeX-style'' quotes. +# smart_quotes: false \ No newline at end of file diff --git a/samples/config_disable_quotes.yml b/samples/config_disable_quotes.yml new file mode 100644 index 0000000..a916fff --- /dev/null +++ b/samples/config_disable_quotes.yml @@ -0,0 +1,3 @@ +# If we want to disable smart quoting and only allow explicit quoting within markup, +# use this option +smart_quotes: false diff --git a/samples/config_text_markup.rb b/samples/config_text_markup.rb new file mode 100644 index 0000000..2ea6068 --- /dev/null +++ b/samples/config_text_markup.rb @@ -0,0 +1,15 @@ +require 'squib' + +Squib::Deck.new(config: 'config_text_markup.yml') do + text str: %{"'Yaml ain't markup', he says"}, + x: 10, y: 10, width: 300, height: 200, font: 'Serif 20', + markup: true, hint: :cyan + save_png prefix: 'config_text_' +end + +Squib::Deck.new(config: 'config_disable_quotes.yml') do + text str: %{This has typographic sugar --- and ``explicit'' quotes --- but the quotes are "dumb"}, + x: 10, y: 10, width: 300, height: 200, font: 'Serif 20', + markup: true, hint: :cyan + save_png prefix: 'config_disable_text_' +end \ No newline at end of file diff --git a/samples/config_text_markup.yml b/samples/config_text_markup.yml new file mode 100644 index 0000000..58d3b7f --- /dev/null +++ b/samples/config_text_markup.yml @@ -0,0 +1,8 @@ +# We can configure what characters actually get replaced by quoting them with unicode code points. +lsquote: "\u2018" #note that Yaml wants double quotes here to use escape chars +rsquote: "\u2019" +ldquote: "\u201C" +rdquote: "\u201D" +em_dash: "\u2014" +en_dash: "\u2013" +ellipsis: "\u2026" diff --git a/spec/args/typographer_spec.rb b/spec/args/typographer_spec.rb index c9243d0..cf0b268 100644 --- a/spec/args/typographer_spec.rb +++ b/spec/args/typographer_spec.rb @@ -44,8 +44,8 @@ describe Squib::Args::Typographer do expect(t.process(%{can't})).to eq(%{can\u2019t}) end - it "single quotes inside double quotes" do - expect(t.process(%{"'I can't do that', he said"})).to eq(%{\u201C\u2019I can\u2019t do that\u2019, he said\u201D}) +it "single quotes inside double quotes" do + expect(t.process(%{"'I can't do that', he said"})).to eq(%{\u201C\u2018I can\u2019t do that\u2019, he said\u201D}) end it "replaces the straightforward ones" do diff --git a/spec/data/samples/config_text_markup.rb.txt b/spec/data/samples/config_text_markup.rb.txt new file mode 100644 index 0000000..916fdf5 --- /dev/null +++ b/spec/data/samples/config_text_markup.rb.txt @@ -0,0 +1,52 @@ +cairo: antialias=(["subpixel"]) +cairo: save([]) +cairo: set_source_color([:black]) +cairo: translate([10, 10]) +cairo: rotate([0]) +cairo: move_to([0, 0]) +pango: font_description=([MockDouble]) +pango: text=(["\"'Yaml ain't markup', he says\""]) +pango: markup=(["foo"]) +pango: width=([307200]) +pango: height=([204800]) +pango: wrap=([#]) +pango: ellipsize=([#]) +pango: alignment=([#]) +pango: justify=([false]) +pango: spacing=([0]) +cairo: update_pango_layout([MockDouble]) +cairo: move_to([0, 0]) +cairo: update_pango_layout([MockDouble]) +cairo: show_pango_layout([MockDouble]) +cairo: rounded_rectangle([0, 0, 0, 0, 0, 0]) +cairo: set_source_color([:cyan]) +cairo: set_line_width([2.0]) +cairo: stroke([]) +cairo: restore([]) +surface: write_to_png(["_output/config_text_00.png"]) +cairo: antialias=(["subpixel"]) +cairo: save([]) +cairo: set_source_color([:black]) +cairo: translate([10, 10]) +cairo: rotate([0]) +cairo: move_to([0, 0]) +pango: font_description=([MockDouble]) +pango: text=(["This has typographic sugar --- and ``explicit'' quotes --- but the quotes are \"dumb\""]) +pango: markup=(["foo"]) +pango: width=([307200]) +pango: height=([204800]) +pango: wrap=([#]) +pango: ellipsize=([#]) +pango: alignment=([#]) +pango: justify=([false]) +pango: spacing=([0]) +cairo: update_pango_layout([MockDouble]) +cairo: move_to([0, 0]) +cairo: update_pango_layout([MockDouble]) +cairo: show_pango_layout([MockDouble]) +cairo: rounded_rectangle([0, 0, 0, 0, 0, 0]) +cairo: set_source_color([:cyan]) +cairo: set_line_width([2.0]) +cairo: stroke([]) +cairo: restore([]) +surface: write_to_png(["_output/config_disable_text_00.png"]) diff --git a/spec/samples/samples_regression_spec.rb b/spec/samples/samples_regression_spec.rb index 39ac0fc..0d04e1b 100644 --- a/spec/samples/samples_regression_spec.rb +++ b/spec/samples/samples_regression_spec.rb @@ -51,6 +51,7 @@ describe "Squib samples" do basic.rb cairo_access.rb csv_import.rb + config_text_markup.rb custom_config.rb draw_shapes.rb embed_text.rb diff --git a/squib.sublime-project b/squib.sublime-project index 857278a..c6b3d03 100644 --- a/squib.sublime-project +++ b/squib.sublime-project @@ -24,6 +24,10 @@ "name": "rake run[draw_shapes]", "shell_cmd": "rake run[draw_shapes]", }, + { + "name": "rake run[config_text_markup]", + "shell_cmd": "rake run[config_text_markup]", + }, { "name": "rspec spec/samples/samples_regression_spec.rb", "shell_cmd": "rspec spec/samples/samples_regression_spec.rb", @@ -39,6 +43,7 @@ "shell_cmd": "rspec spec/graphics/graphics_text_spec.rb", "working_dir": "${project_path:${folder}}" }, + ], }