App-Music-ChordPro

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

      of files that the 'classic' GUI suffers from.
      Thanks Nick!

    - ChordPro bundles free replacement fonts to be used instead of
      the corefonts. No configs or settings needed.

    !Functionality
    - (PDF, page sort) Use sorttitle for page sorting.
    - Images: Ignore align with x percentage. Issue warning.
    - Detection of attributes in labels now requires quoting.
    - Handle \u escapes for surrogates and extended chars (\u{...}).
    - 'chordpro -A -A -A' will produce runtime info in JSON.
    - Add '--convert-config' to convert config to new style.
    - Add href property for images.
    - New metadata: chordpro, chordpro.version and chordpro.songsource.
    - Upgrade JSON::Relaxed to 0.096.
    - Upgrade SVGPDF to 0.087. Enables transparent SVG images.
    - Add independent horizontal and vertical scaling for images.
      Requires Text::Layout 0.037_002.
    - Upgrade Text::Layout to 0.038.
    - Allow fret -1 in {define}, and 'x' in json config for consistency.

Changes  view on Meta::CPAN

    - Fix problem that titles-directive-ignore was ignored.
    - (PDF) Fix problem that toc entries were not clickable.
    - Fix issue #41 - Error in transposition of a recalled chorus.
    - Fix issue #42 - Defining Chords Fails for Songbooks.
      Song chord definitions were lost in multi-song songbooks except
      for the last (or only) song.
    - Fix schema validation for configs.

0.94	2018-01-23

    - Allow \ { } and | to be escaped with \ in replacement strings.
    - Fix problem that in-song chords caused CANNOT HAPPEN error.
    - Add --filelist option to read song file names from files.
    - Fix inconsistent handling of --lyrics-only in backends.
    - Add html to list of recognized output types (even though
      experimental). Note that the HTML backend is not yet included.
    - Fix Chord/Chordii regression: Base frets in chord diagrams
      should be arabic numbers, not roman.
    - Pass unknown directives through to backends.
    - Fix labels handling for ChordPro output.
    - Fix problem that bass notes in chords were not transposed.

MANIFEST  view on Meta::CPAN

t/210_configs.t
t/211_config.t
t/212_config.t
t/21_basic02_crd.t
t/30_basic01_cho.t
t/310_basic.t
t/311_keys.t
t/312_context.t
t/313_null.t
t/314_data.t
t/315_escape.t
t/316_array.t
t/317_empty.t
t/31_basic02_cho.t
t/320_subst.t
t/321_subst.t
t/322_subst.t
t/323_null.t
t/380_roundtrip.t
t/400_kv.t
t/40_basic01_html.t

lib/ChordPro/Config.pm  view on Meta::CPAN

	my $cfg = Data::Properties->new;
	$cfg->parse_file($from);
	$new = $cfg->data;
    }
    else {			# assume JSON, RJSON, RRJSON
	$new = $parser->decode($data);
    }

    # And re-encode it using the schema.
    my $res = $parser->encode( data => $new, pretty => 1,
			       nounicodeescapes => 1, schema => $schema );
    # use DDP; p $res;
    # Add trailer.
    $res .= "\n// End of Config.\n";

    # Write if out.
    if ( $to && $to ne "-" ) {
	open( my $fd, '>', $to )
	  or die("$to: $!\n");
	print $fd $res;
	$fd->close;

lib/ChordPro/Config/Properties.pm  view on Meta::CPAN

Whitespace has no significance. A colon C<:> may be used instead of
C<=>. Lines that are blank or empty, and lines that start with C<#>
are ignored.

Property I<names> consist of one or more identifiers (series of
letters and digits) separated by periods.

Valid values are a plain text (whitespace, but not trailing, allowed),
a single-quoted string, or a double-quoted string. Single-quoted
strings allow embedded single-quotes by escaping them with a backslash
C<\>. Double-quoted strings allow common escapes like C<\n>, C<\t>,
C<\7>, C<\x1f> and C<\x{20cd}>.

Note that in plain text backslashes are taken literally. The following
alternatives yield the same results:

    foo = a'\nb
    foo = 'a\'\nb'
    foo = "a'\\nb"

B<IMPORTANT:> All values are strings. These three are equivalent:

lib/ChordPro/Dumper.pm  view on Meta::CPAN

no warnings qw( experimental::signatures );
use utf8;

package ChordPro::Dumper;

use Exporter qw(import);
our @EXPORT = qw(ddp);

use Data::Printer
  hash_separator  => " => ",
  escape_chars	  => "nonascii",
  print_escapes	  => 1,
  scalar_quotes	  => "'",
  caller_message_newline => 0,
  string_max      => 120,
  class => { parents    => 0,
	     linear_isa => 0,
	     show_methods    => "none",
	     show_overloads  => 0,
	     internals	     => 1 };

my $filters = [

lib/ChordPro/Output/Markdown.pm  view on Meta::CPAN

    foreach ( 0..$#{$elt->{chords}} ) {
		$c_line .= chord( $elt->{chords}->[$_] ) . " ";
		$t_line .= $phrases[$_];
		my $d = length($c_line) - length($t_line);
		$t_line .= "-" x $d if $d > 0;
		$c_line .= " " x -$d if $d < 0;
    } # this looks like setting the chords above the words.

    s/\s+$// for ( $t_line, $c_line );

	# main problem in markdown - a fixed position is only available in "Code escapes" so weather to set
	# a tab or a double backticks (``)  - i tend to the tab - so all lines with tabs are "together"
	if ($c_line ne ""){ # Block-lines are not replacing initial spaces - as the are "code"
		$t_line = $cp.$t_line."  ";
		$c_line = $cp.$c_line."  ";
		}
	else{
		$t_line = md_textline($cp.$t_line);
	}
	return $chords_under
		? ( $t_line, $c_line )

lib/ChordPro/Output/PDF/Song.pm  view on Meta::CPAN


sub prlabel {
    my ( $ps, $label, $x, $y ) = @_;
    return if $label eq "" || $ps->{_indent} == 0;
    my $align = $ps->{labels}->{align};
    my $font= $ps->{fonts}->{label} || $ps->{fonts}->{text};
    $font->{size} ||= $font->{fd}->{size};
    $ps->{pr}->setfont($font);	# for strwidth.

    # Now we have quoted strings we can have real newlines.
    # Split on real and unescaped (old style) newlines.
    for ( split( /\\n|\n/, $label ) ) {
	my $label = $_;
	if ( $align eq "right" ) {
	    my $avg_space_width = $ps->{pr}->strwidth("m");
	    $ps->{pr}->text( $label,
			     $x - $avg_space_width - $ps->{pr}->strwidth($label),
			     $y, $font );
	}
	elsif ( $align =~ /^cent(?:er|re)$/ ) {
	    $ps->{pr}->text( $label,

lib/ChordPro/Song.pm  view on Meta::CPAN


	$_ = shift(@$lines);
	while ( /\\\Z/ && @$lines ) {
	    chop;
	    my $cont = shift(@$lines);
	    $$linecnt++;
	    $cont =~ s/^\s+//;
	    $_ .= $cont;
	}

	# Uncomment this to allow \uDXXX\uDYYY (surrogate) escapes.
	s/ \\u(d[89ab][[:xdigit:]]{2})\\u(d[cdef][[:xdigit:]]{2})
	 / pack('U*', 0x10000 + (hex($1) - 0xD800) * 0x400 + (hex($2) - 0xDC00) )
	   /igex;

	# Uncomment this to allow \uXXXX escapes.
	s/\\u([0-9a-f]{4})/chr(hex("0x$1"))/ige;
	# Uncomment this to allow \u{XX...} escapes.
	s/\\u\{([0-9a-f]+)\}/chr(hex("0x$1"))/ige;

	$diag->{orig} = $_;
	# Get rid of TABs.
	s/\t/ /g;

	if ( $config->{debug}->{echo} ) {
	    warn(sprintf("==[%3d]=> %s\n", $diag->{line}, $diag->{orig} ) );
	}

lib/ChordPro/Wx/Main.pm  view on Meta::CPAN

				       $self->can("OnSysColourChanged") );
    $self->init_theme;

    if ( @ARGV ) {
	# use DDP;
	use charnames ':full';
	require _charnames;
	push( @{$state{msgs}},
	      "ARGV: " . np(@ARGV,
			      show_unicode => 1,
			      escape_chars => 'nonascii',
			      unicode_charnames => 1 ) ) if 0;
	my $arg = shift(@ARGV);	# ignore rest
	$arg = decode_utf8($arg);
	push( @{$state{msgs}},
	      'DECODED: ' . np($arg,
			    show_unicode => 1,
			    escape_chars => 'nonascii',
			    unicode_charnames => 1 ) ) if 0;

	if ( fs_test( 'd', $arg ) ) {
	    return 1 if $self->select_mode("sbexport")->open_dir($arg);
	}
	elsif ( !fs_test( 'r', $arg ) ) {
	    return 1 if $self->select_mode("editor")->newfile($arg);
	    Wx::MessageDialog->new( $self, "Error opening $arg",
				    "File Open Error",
				    wxOK | wxICON_ERROR )->ShowModal;

lib/ChordPro/Wx/RenderDialog.wxg  view on Meta::CPAN

<?xml version="1.0"?>
<!-- generated by wxGlade 1.1.0 on Fri Nov 29 21:52:11 2024 -->

<application encoding="UTF-8" for_version="2.8" header_extension=".h" indent_amount="4" indent_symbol="space" is_template="0" language="perl" mark_blocks="1" option="0" overwrite="1" path="RenderDialog_wxg.pm" source_extension=".cpp" top_window="d_pr...
    <object class="ChordPro::Wx::RenderDialog_wxg" name="d_prefs" base="EditDialog">
        <extracode_pre>use ChordPro::Wx::Utils;</extracode_pre>
        <title>Preview Tasks</title>
        <style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</style>
        <affirmative>b_ok</affirmative>
        <escape>b_cancel</escape>
        <object class="wxBoxSizer" name="sz_prefs_outer" base="EditBoxSizer">
            <orient>wxVERTICAL</orient>
            <object class="sizeritem">
                <option>0</option>
                <border>5</border>
                <flag>wxALL|wxEXPAND</flag>
                <object class="wxStaticText" name="label_3" base="EditStaticText">
                    <foreground>#0068d9</foreground>
                    <font>
                        <size>18</size>

lib/ChordPro/lib/Data/Printer/Theme/Zellner.pm  view on Meta::CPAN

        code        => '#870087',    # code references
        glob        => '#870087',    # globs (usually file handles)
        vstring     => '#ff00ff',    # version strings (v5.30.1, etc)
        lvalue      => '#000000',    # lvalue label
        format      => '#000000',    # format type
        repeated    => '#000000',    # references to seen values
        caller_info => '#878787',    # details on what's being printed
        weak        => '#000000',    # weak references flag
        tainted     => '#870000',    # tainted flag
        unicode     => '#000000',    # utf8 flag
        escaped     => '#ff00ff',    # escaped characters (\t, \n, etc)
        brackets    => '#000000',    # (), {}, []
        separator   => '#000000',    # the "," between hash pairs, array elements, etc
        quotes      => '#000000',    # q(")
        unknown     => '#878787',    # any (potential) data type unknown to Data::Printer
    };
}

1;

=pod

lib/ChordPro/lib/Data/Printer/Theme/Zellner.pm  view on Meta::CPAN

        code        => '#870087',    # code references
        glob        => '#870087',    # globs (usually file handles)
        vstring     => '#ff00ff',    # version strings (v5.30.1, etc)
        lvalue      => '#000000',    # lvalue label
        format      => '#000000',    # format type
        repeated    => '#000000',    # references to seen values
        caller_info => '#878787',    # details on what's being printed
        weak        => '#000000',    # weak references flag
        tainted     => '#870000',    # tainted flag
        unicode     => '#000000',    # utf8 flag
        escaped     => '#ff00ff',    # escaped characters (\t, \n, etc)
        brackets    => '#000000',    # (), {}, []
        separator   => '#000000',    # the "," between hash pairs, array elements, etc
        quotes      => '#000000',    # q(")
        unknown     => '#878787',    # any (potential) data type unknown to Data::Printer

=head1 COPYRIGHT

E<copy> MMXXIII - Abe Timmerman <abeltje@cpan.org>

=head1 CONTRIBUTIONS

lib/ChordPro/lib/JSON/Relaxed.pm  view on Meta::CPAN

Note that this is different from

      "this is a \
    long string"

which B<embeds> the newline into the string, and requires continuation
lines to start at the beginning of the line to prevent unwanted spaces.

Enabled by default, overruled by C<strict>.

=head2 Extended Unicode escapes

Unicode escapes in strings may contain an arbitrary number of hexadecimal
digits enclosed in braces:

    \u{1d10e}

This eliminates the need to use
L<surrogates|https://unicode.org/faq/utf_bom.html#utf16-2>
to obtain the same character:

    \uD834\uDD0E

lib/ChordPro/lib/JSON/Relaxed.pm  view on Meta::CPAN


=over 4

=item *

Numbers will be output as numbers.

=item *

Strings will be output as unquoted strings if possible, quoted strings
otherwise. Non-latin characters will be output as C<\u> escapes.
When some of the quotes C<" ' `> are embedded the others will be tried
for the string, e.g. C<"a\"b"> will yield C<'a"b'>.

All quotes are equal, there is no difference in interpretation.

=item *

Boolean objects will be output as unquoted C<true> and C<false>.

=item *

lib/ChordPro/lib/JSON/Relaxed/Parser.pm  view on Meta::CPAN


method is_quote ($c) {
    $c =~ /^$p_quotes$/o;
}

# Numbers. A special case of unquoted strings.
my $p_number = q{[+-]?\d*\.?\d+(?:[Ee][+-]?\d+)?};

method pretokenize {

    # \u escape (4 hexits)
    my @p = ( qq<\\\\u[[:xdigit:]]{4}> );

    # Any escaped char (strict mode).
    if ( $strict ) {
	push( @p, qq<\\\\.> );
    }

    # Otherwise, match \u{ ... } also.
    else {
	push( @p, qq<\\\\u\\{[[:xdigit:]]+\\}>, qq<\\\\[^u]> ); # escaped char
    }

    if ( $prp && !$strict ) {
	# Add = to the reserved characters
        $p_reserved = q<[,=:{}\[\]]>;
	# Massage # comments into // comments without affecting position.
        $data =~ s/^(\s*)#.(.*)$/$1\/\/$2/gm;
        $data =~ s/^(\s*)#$/$1 /gm;
    }

lib/ChordPro/lib/JSON/Relaxed/Parser.pm  view on Meta::CPAN

method encode(%opts) {
    my $schema  = $opts{schema};
    my $level   = $opts{level}              // 0;
    my $rv      = $opts{data};			# allow undef
    my $indent  = $opts{indent}             // 2;
    my $impoh   = $opts{implied_outer_hash} // $implied_outer_hash;
    my $ckeys   = $opts{combined_keys}      // $combined_keys;
    my $prpmode = $opts{prp}                // $prp;
    my $pretty  = $opts{pretty}             // $pretty;
    my $strict  = $opts{strict}             // $strict;
    my $nouesc  = $opts{nounicodeescapes}   // 0;

    if ( $strict ) {
	$ckeys = $prpmode = $impoh = 0;
    }

    $schema = resolve( $schema, $schema ) if $schema;

    my $s = "";
    my $i = 0;
    my $props = $schema->{properties};

lib/ChordPro/lib/JSON/Relaxed/Parser.pm  view on Meta::CPAN

	$v =~ s/\\/\\\\/g;
	$v =~ s/\n/\\n/g;
	$v =~ s/\r/\\r/g;
	$v =~ s/\f/\\f/g;
	$v =~ s/\013/\\v/g;
	$v =~ s/\010/\\b/g;
	$v =~ s/\t/\\t/g;
	$v =~ s/([^ -ÿ])/sprintf( ord($1) < 0xffff ? "\\u%04x" : "\\u{%x}", ord($1))/ge unless $nouesc;

	# Force quotes unless the string can be represented as unquoted.
	if ( # contains escapes
	     $v ne $str
	     # not value-formed numeric
	     || ( $v =~ /^$p_number$/ && 0+$v ne $v )
	     # contains reserved, quotes or spaces
	     || $v =~ $p_reserved
	     || $v =~ $p_quotes
	     || $v =~ /\s/
	     || $v =~ /^(true|false|null)$/
	     || !length($v)
	   ) {

lib/ChordPro/lib/JSON/Relaxed/Parser.pm  view on Meta::CPAN

	# If we have a key order, use this and delete.
	my @ko = $rv->{" key order "}
	  ? @{ delete($rv->{" key order "}) }
	  : sort(keys(%$rv));

	# Dedup.
	@ko = uniqstr(@ko);

	my $ll = 0;
	for ( @ko ) {
	    # This may be wrong if \ escapes or combined keys are involved.
	    $ll = length($_) if length($_) > $ll;
	}

	for ( @ko ) {
	    my $k = $_;

	    # Gather comments, if available.
	    my $comment;
	    if ( $props->{$k} ) {
		$comment = $comments->($props->{$k});

lib/ChordPro/lib/JSON/Relaxed/Parser.pm  view on Meta::CPAN


=cut

################ Strings ################

class JSON::Relaxed::String :isa(JSON::Relaxed::Token);

field $content	:param = undef;
field $quote	:accessor :param = undef;

# Quoted strings are assembled from complete substrings, so escape
# processing is done on the substrings. This prevents ugly things
# when unicode escapes are split across substrings.
# Unquotes strings are collected token by token, so escape processing
# can only be done on the complete string (on output).

ADJUST {
    $content = $self->unescape($content) if defined($quote);
};

method append ($str) {
    $str = $self->unescape($str) if defined $quote;
    $content .= $str;
}

method content {
    defined($quote) ? $content : $self->unescape($content);
}

# One regexp to match them all...
my $esc_quoted = qr/
	       \\([tnrfb])				# $1 : one char
	     | \\u\{([[:xdigit:]]+)\}			# $2 : \u{XX...}
	     | \\u([Dd][89abAB][[:xdigit:]]{2})		# $3 : \uDXXX hi
	       \\u([Dd][c-fC-F][[:xdigit:]]{2})		# $4 : \uDXXX lo
	     | \\u([[:xdigit:]]{4})			# $5 : \uXXXX
	     | \\?(.)					# $6
	   /xs;

# Special escapes (quoted strings only).
my %esc = (
    'b'   => "\b",    #  Backspace
    'f'   => "\f",    #  Form feed
    'n'   => "\n",    #  New line
    'r'   => "\r",    #  Carriage return
    't'   => "\t",    #  Tab
    'v'   => chr(11), #  Vertical tab
);

method unescape ($str) {
    return $str unless $str =~ /\\/;

    my $convert = sub {
	# Specials. Only for quoted strings.
	if ( defined($1) ) {
	    return defined($quote) ? $esc{$1} : $1;
	}

	# Extended \u{XXX} character.
	defined($2) and return chr(hex($2));

lib/ChordPro/res/abc/abc2svg/abc2svg-1.js  view on Meta::CPAN


// accidentals as octal values (abcm2ps compatibility)
var oct_acc = {
	"1": "\u266f",
	"2": "\u266d",
	"3": "\u266e",
	"4": "&#x1d12a;",
	"5": "&#x1d12b;"
}

// convert the escape sequences to utf-8
function cnv_escape(src, flag) {
	var	c, c2,
		dst = "",
		i, j = 0

	while (1) {
		i = src.indexOf('\\', j)
		if (i < 0)
			break
		dst += src.slice(j, i);
		c = src[++i]

lib/ChordPro/res/abc/abc2svg/abc2svg-1.js  view on Meta::CPAN

		re.lastIndex = i;
		res = re.exec(file)
		if (res)
			eol = re.lastIndex
		else
			eol = eof
		return false
	} // tune_selected()

	// remove the comment at end of text
	// if flag, handle the escape sequences
	// if flag is 'w' (lyrics), keep the '\'s
	function uncomment(src, flag) {
		if (!src)
			return src
	    var	i = src.indexOf('%')
		if (i == 0)
			return ''
		if (i > 0)
			src = src.replace(/([^\\])%.*/, '$1')
				 .replace(/\\%/g, '%');
		src = src.replace(/\s+$/, '')
		if (flag && src.indexOf('\\') >= 0)
			return cnv_escape(src, flag)
		return src
	} // uncomment()

	function end_tune() {
		generate()
		cfmt = sav.cfmt;
		info = sav.info;
		char_tb = sav.char_tb;
		glovar = sav.glovar;
		maps = sav.maps;

lib/ChordPro/res/abc/abc2svg/abc2svg-1.js  view on Meta::CPAN

			curvoice.score = cfmt.sound ? curvoice.sound : val
			tr_p |= 1
			break
		case "map=":			// %%voicemap
			curvoice.map = a.shift()
			break
		case "name=":
		case "nm=":
			curvoice.nm = a.shift()
			if (curvoice.nm[0] == '"')
				curvoice.nm = cnv_escape(curvoice.nm.slice(1, -1))
			curvoice.new_name = true
			break
		case "stem=":			// compatibility
		case "pos=":			// from %%pos only
			if (item == "pos=")
				item = a.shift()
					.slice(1, -1)	// always inside dble quotes
					.split(' ')
			else
				item = ["stm", a.shift()];

lib/ChordPro/res/abc/abc2svg/abc2svg-1.js  view on Meta::CPAN

			}
			defs_add(text.slice(i + 6, j))
		}
		break
	case "text":
		action = get_textopt(opt);
		if (!action)
			action = cfmt.textoption
		set_font("text")
		if (text.indexOf('\\') >= 0)
			text = cnv_escape(text)
		if (parse.state > 1) {
			s = new_block(type);
			s.text = text
			s.opt = action
			s.font = cfmt.textfont
			break
		}
		write_text(text, action)
		break
	}

lib/ChordPro/res/abc/abc2svg/abc2svg-1.js  view on Meta::CPAN

			j = line.buffer.indexOf('"', i)
			if (j < 0) {
				syntax(1, "No end of chord symbol/annotation")
				return
			}
			if (line.buffer[j - 1] != '\\'
			 || line.buffer[j - 2] == '\\')	// (string ending with \\")
				break
			i = j + 1
		}
		text = cnv_escape(line.buffer.slice(line.index, j))
		line.index = j
		iend = parse.bol + line.index + 1
	}

	if (ann_font.pad)
		h_ann += ann_font.pad
	i = 0;
	type = 'g'
	while (1) {
		c = text[i]

lib/ChordPro/res/abc/abc2svg/abc2svg-1.js  view on Meta::CPAN

Abc.prototype.gch_build = function(s) {

	/* split the chord symbols / annotations
	 * and initialize their vertical offsets */
	var	gch, wh, xspc, ix,
		y_left = 0,
		y_right = 0,
		GCHPRE = .4;		// portion of chord before note

	// change the accidentals in the chord symbols,
	// convert the escape sequences in annotations, and
	// set the offsets
	for (ix = 0; ix < s.a_gch.length; ix++) {
		gch = s.a_gch[ix]
		if (gch.type == 'g') {
			gch.text = gch.text.replace(/##|#|=|bb|b/g,
				function(x) {
					switch (x) {
					case '##': return "&#x1d12a;"
					case '#': return "\u266f"
					case '=': return "\u266e"

lib/ChordPro/res/config/config.schema  view on Meta::CPAN

              ],
              "default": "pct_chords"
            }
          }
        }
      }
    },
    {
      "title": "Settings for the parser/preprocessor",
      "type": "object",
      "description": "For selected lines, you can specify a series of `{ \"target\" : \"xxx\", \"replace\" : \"yyy\" }`.\nEvery occurrence of \"xxx\" will be replaced by \"yyy\".\nUse \"pattern\" instead of \"target\" for regular expression replaceme...
      "properties": {
        "parser": {
          "$ref": "#/definitions/parserspec",
          "description": "Settings for the parser/preprocessor.\nFor selected lines, you can specify a series of \n{ \"target\" : \"xxx\", \"replace\" : \"yyy\" }\nEvery occurrence of \"xxx\" will be replaced by \"yyy\".\nUse \"pattern\" instead of \...
        }
      }
    },
    {
      "title": "Text Output",
      "type": "object",

t/10_files.t  view on Meta::CPAN

    }
}

is( 0+keys(%files), 0, "All files found" );

sub dd {
    return;
    use DDP;
    diag np( $_[0],
	     show_unicode => 1,
	     escape_chars=>'nonascii',
	     unicode_charnames => 1,
	     $_[1] ? ( as => $_[1] ) : () );
}



( run in 0.537 second using v1.01-cache-2.11-cpan-c21f80fb71c )