#!/usr/bin/env perl # # Output as Format: read from stdin and output it as code in the given format # https://github.com/sshaw/output-as-format # # Based off copy-as-format for Emacs: https://github.com/sshaw/copy-as-format # # Copyright (c) 2017-2019 Skye Shaw # # This library is free software; you can redistribute it and/or modify # it under the same terms as Perl itself. # use strict; use warnings; package Util; sub html_escape { my $text = shift; my %escapes = ('&' => '&', '<' => '<'); $$text =~ s/[&<]/$escapes{$&}/eg; } sub indent { my ($text, $n) = @_; $$text =~ s/^/' ' x $n/gme; } # Should just do Markdown->quote, Markdown->list, etc... package Quote; sub html { my $lines = shift; print '
',"\n"; for (@$lines) { Util::html_escape(\$_); print $_,"\n"; } print '
',"\n"; } sub jira { my ($lines, $multiline) = @_; if ($multiline) { print '{quote}',"\n"; printf "%s\n", $_ for @$lines; print '{quote}',"\n"; } else { printf "bq. %s\n", join ' ', @$lines } } sub orgmode { my $lines = shift; print "#+BEGIN_QUOTE\n"; print $_,"\n" for @$lines; print "#+END_QUOTE\n"; } sub markdown { my $lines = shift; printf "> %s\n", $_ for @$lines; } sub output { shift; my ($format, $multiline) = @_; my $lines = []; die "unsupported quote format: $format\n" unless $Quote::{$format}; while () { chomp; s/^\s*//g; push @$lines, $_; } $multiline = @$lines > 1 ? 1 : 0 unless defined($multiline); $Quote::{$format}->($lines, $multiline); } $Quote::{$_} = *markdown for qw(github slack); package List; sub html { my ($lines, $numbered) = @_; my $li = sub { for (@$lines) { Util::html_escape(\$_); printf '
  • %s
  • ', $_; } }; if ($numbered) { print '
      '; $li->(); print '
    '; } else { print ''; } } # mediawiki too sub markdown { my ($lines, $numbered) = @_; my $prefix = $numbered ? '1.' : '*'; printf "%s %s\n", $prefix, $_ for @$lines; } sub jira { my ($lines, $numbered) = @_; my $prefix = $numbered ? '#' : '*'; printf "%s %s\n", $prefix, $_ for @$lines; } sub orgmode { my ($lines, $numbered) = @_; my $n = 1; printf "%s %s\n", $numbered ? $n++ . '.' : '-', $_ for @$lines; } sub rst { # Bullet lists are the same as Markdown return markdown(shift) unless pop; my $lines = shift; printf "#. %s\n", $_ for @$lines; } sub pod { # Numbered my $lines = shift; print '=over 2',"\n"; printf "=item %s\n" for @$lines; print '=back'; } sub output { shift; my ($format, $numbered) = @_; my $lines = []; die "unsupported list format: $format\n" unless $List::{$format}; while () { chomp; s/^\s*//g; push @$lines, $_; } $List::{$format}->($lines, $numbered); } $List::{$_} = *markdown for qw(github slack); package Code; sub output { shift; my ($format, $lang, $multiline) = @_; my @indents; my $snippet = ''; while () { s/\t/' ' x 8/eg; $snippet .= $_; push @indents, /^(\s*)/ && length $1; } exit 1 unless @indents; # Remove the minimum amount of leading white space my $trim = (sort { $a <=> $b } @indents)[0]; $snippet =~ s/^\s{$trim}//mg; # Remove newline for single line input chomp $snippet if @indents == 1; $multiline = @indents > 1 ? 1 : 0 unless defined($multiline); $Code::{$format}->($snippet, $multiline, $lang); } sub disqus { my ($snippet, undef, $lang) = @_; Util::html_escape(\$snippet); printf "
    \n%s
    \n", $lang || '', $snippet; } sub github { my ($snippet, $multiline, $lang) = @_; if ($multiline) { printf "```%s\n%s```\n", $lang || '', $snippet; } else { printf '`%s`', $snippet; } } sub hipchat { my $snippet = shift; printf '/code %s', $snippet; } sub html { my ($snippet, $multiline, $lang) = @_; Util::html_escape(\$snippet); if ($multiline) { printf "
    \n%s
    ", $snippet; } else { printf '%s', $snippet; } } sub jira { my ($snippet, $multiline, $lang) = @_; if ($multiline) { printf "{code%s}\n%s{code}\n", $lang ? ":$lang" : '', $snippet; } else { printf '{{%s}}', $snippet; } } sub markdown { my ($snippet, $multiline) = @_; if ($multiline) { Util::indent(\$snippet, 4); print $snippet; } else { printf '`%s`', $snippet; } } sub mediawiki { my ($snippet, $multiline, $lang) = @_; my $markup = sprintf '\n%s", $snippet; print $markup; } sub orgmode { my ($snippet, $multiline, $lang) = @_; if ($multiline) { printf "#+BEGIN_SRC %s\n%s\n#+END_SRC\n", $lang || '', $snippet; } else { # Cannot escape '~' within Org-mode's code formatting # entities and empty space don't work. printf '~%s~', $snippet; } } sub pod { my ($snippet, $multiline, $lang) = @_; if ($multiline) { Util::indent(\$snippet, 2); print $snippet; } else { $snippet =~ s/<E/g; printf 'C<< %s >>', $snippet; } } sub rst { my ($snippet, $multiline, $lang) = @_; if ($multiline) { Util::indent(\$snippet, 4); printf ".. code::\n\n%s\n", $snippet; } else { printf '``%s``', $snippet; } } sub slack { my ($snippet, $multiline) = @_; if ($multiline) { printf "```\n%s```\n", $snippet; } else { $snippet =~ s/^\s+|\s+$//g; printf '`%s`', $snippet; } } package main; use Getopt::Long qw(:config no_ignore_case); our $VERSION = '0.04'; sub HELP_MESSAGE { my $out = shift; print $out < 'github', disqus => 'disqus', github => 'github', gitlab => 'github', hipchat => 'hipchat', html => 'html', jira => 'jira', markdown => 'markdown', mediawiki => 'mediawiki', orgmode => 'orgmode', pod => 'pod', rst => 'rst', slack => 'slack'); GetOptions('f=s' => \$options{f}, 'h|help' => sub { HELP_MESSAGE(*STDOUT) and exit }, 'l=s' => \$options{l}, 'list|L' => \$options{list}, 'list1|1' => \$options{list1}, 'm' => \$options{m}, 'p' => \$options{p}, 'quote|Q' => \$options{quote}, 's' => \$options{s}, 'v|version' => sub { VERSION_MESSAGE(*STDOUT) and exit } ) or HELP_MESSAGE(*STDERR) and exit 1; if ($options{p}) { local $\= "\n"; print for sort keys %formats; exit; } my $lang = $options{l} || $ENV{OAF_LANG}; my $multiline = $options{m}; $multiline = 0 if $options{s}; # FIXME: use GetOptions for this..? my $format = $options{f} || $ENV{OAF_FORMAT} || 'markdown'; die "Unknown format: $format\n" unless $formats{$format}; # ====== if ($options{list} || $options{list1}) { my $numbered = $options{list1} || 0; List->output($formats{$format}, $numbered); } elsif ($options{quote}) { Quote->output($formats{$format}, $multiline); } else { Code->output($formats{$format}, $lang, $multiline); }