aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Spek <p.spek@tyil.nl>2020-02-02 18:04:53 +0100
committerPatrick Spek <p.spek@tyil.nl>2020-02-02 18:04:53 +0100
commitf16a0b531c0f8d11525fa22c20eb4babc3b98458 (patch)
tree4025257aff7bf2bd294f5d8cc3a6a45e404f481e
downloadApp::Rakuman-f16a0b531c0f8d11525fa22c20eb4babc3b98458.tar.gz
App::Rakuman-f16a0b531c0f8d11525fa22c20eb4babc3b98458.tar.bz2
Initial commit
-rw-r--r--.editorconfig16
-rw-r--r--.gitignore14
-rw-r--r--.gitlab-ci.yml23
-rw-r--r--.travis.yml13
-rw-r--r--CHANGELOG.md9
-rw-r--r--META6.json27
-rw-r--r--README.pod623
-rw-r--r--bin/rakuman23
-rw-r--r--lib/App/Rakuman.pm6137
-rw-r--r--lib/App/Rakuman/Bin.pm640
-rw-r--r--lib/Pod/To/Rakuman.pm6231
11 files changed, 556 insertions, 0 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..74dde7f
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,16 @@
+[*]
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
+indent_style = tab
+indent_size = 4
+
+[*.json]
+indent_style = space
+indent_size = 2
+
+[*.yml]
+indent_style = space
+indent_size = 2
+
+# vim: ft=dosini
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..93356c2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,14 @@
+## Perl 6 precompilation files ##
+.precomp
+
+## Editor files ##
+
+# emacs
+*~
+
+# vim
+.*.sw?
+
+# comma
+.idea
+*.iml
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..f28f430
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,23 @@
+App::Rakuman:
+ only:
+ - master
+ image: rakudo-star
+ before_script:
+ - zef install . --deps-only --test-depends --/test
+ script: AUTHOR_TESTING=1 prove -v -e "perl6 -Ilib" t
+ artifacts:
+ name: "perl6-App-Rakuman"
+ paths:
+ - META6.json
+ - bin
+ - lib
+ - resources
+ - t
+
+test:
+ except:
+ - master
+ image: rakudo-star
+ before_script:
+ - zef install . --deps-only --test-depends --/test
+ script: AUTHOR_TESTING=1 prove -v -e "perl6 -Ilib" t
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..077ddb0
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,13 @@
+language: perl6
+
+perl6:
+ - latest
+
+os:
+ - linux
+
+install:
+ - rakudobrew build zef
+ - zef install --deps-only .
+
+script: AUTHOR_TESTING=1 prove -v -e "perl6 -Ilib" t/
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..1003abb
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,9 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic
+Versioning](http://semver.org/spec/v2.0.0.html).
+
+## [UNRELEASED]
+- Initial release
diff --git a/META6.json b/META6.json
new file mode 100644
index 0000000..d6569c7
--- /dev/null
+++ b/META6.json
@@ -0,0 +1,27 @@
+{
+ "api": "0",
+ "authors": [
+ "Patrick Spek <p.spek@tyil.work>"
+ ],
+ "depends": [
+ "JSON::Fast",
+ "Pod::To::Anything"
+ ],
+ "description": "A program to read the main Pod6 document of Raku modules",
+ "license": "AGPL-3.0",
+ "meta-version": 0,
+ "name": "App::Rakuman",
+ "perl": "6.d",
+ "provides": {
+ "App::Rakuman": "lib/App/Rakuman.pm6",
+ "App::Rakuman::Bin": "lib/App/Rakuman/Bin.pm6",
+ "Pod::To::Rakuman": "lib/Pod/To/Rakuman.pm6",
+ "rakuman": "bin/rakuman"
+ },
+ "resources": [
+ ],
+ "source-url": "",
+ "tags": [
+ ],
+ "version": "0.0.0"
+} \ No newline at end of file
diff --git a/README.pod6 b/README.pod6
new file mode 100644
index 0000000..127adca
--- /dev/null
+++ b/README.pod6
@@ -0,0 +1,23 @@
+=begin pod
+
+=NAME App::Rakuman
+=AUTHOR Patrick Spek <p.spek@tyil.work>
+=VERSION 0.0.0
+
+=head1 Description
+
+A program to read the main Pod6 document of Raku modules
+
+=head1 Installation
+
+Install this module through L<zef|https://github.com/ugexe/zef>:
+
+=begin code :lang<sh>
+zef install App::Rakuman
+=end code
+
+=head1 License
+
+This module is distributed under the terms of the AGPL-3.0.
+
+=end pod
diff --git a/bin/rakuman b/bin/rakuman
new file mode 100644
index 0000000..7a42cb1
--- /dev/null
+++ b/bin/rakuman
@@ -0,0 +1,23 @@
+#! /usr/bin/env perl6
+
+use v6.d;
+
+use App::Rakuman::Bin;
+
+=begin pod
+
+=NAME rakuman
+=AUTHOR Patrick Spek <p.spek@tyil.work>
+=VERSION 0.0.0
+
+=head1 Synopsis
+
+=head1 Description
+
+=head1 Examples
+
+=head1 See also
+
+=end pod
+
+# vim: ft=perl6 noet
diff --git a/lib/App/Rakuman.pm6 b/lib/App/Rakuman.pm6
new file mode 100644
index 0000000..2e92419
--- /dev/null
+++ b/lib/App/Rakuman.pm6
@@ -0,0 +1,137 @@
+#! /usr/bin/env false
+
+use v6.d;
+
+use JSON::Fast;
+use File::Temp;
+
+unit module App::Rakuman;
+
+#| Render a local file's Pod6 document.
+multi sub rakuman (
+ Str:D $path,
+ Bool:D :$skip-pager = False,
+ Bool:D :$try-resolving where !*,
+ --> Int
+) is export {
+ # Extract only the relevant parts
+ my ($filename, $filehandle) = tempfile;
+
+ for $path.IO.lines {
+ state $pod = False;
+
+ if ($_.trim.fc eq '=begin pod') {
+ $pod++;
+ $filehandle.say('=begin pod');
+ next;
+ }
+
+ if (!$pod) {
+ next;
+ }
+
+ if ($_.trim.fc eq '=end pod') {
+ $filehandle.say('=end pod');
+ $filehandle.close();
+ last;
+ }
+
+ $filehandle.say($_);
+ }
+
+ my $command = "'$*EXECUTABLE' -Ilib --doc=Rakuman '$filename'";
+
+ if (!$skip-pager) {
+ my Str $pager = %*ENV<PAGER> // ($*DISTRO.is-win ?? 'more' !! 'less -r');
+
+ $command ~= " | $pager";
+ }
+
+ shell $command;
+
+ 0;
+}
+
+#| Render an Pod6 document of an installed module.
+multi sub rakuman (
+ Str:D $module,
+ Bool:D :$skip-pager = False,
+ Bool:D :$try-resolving where *,
+ --> Int
+) is export {
+ my $path = rakuman-resolve($module);
+
+ # Ensure a module was resolved.
+ if (!$path) {
+ note "No file found for $module";
+ return 3;
+ }
+
+ # Run rakuman with the resolved file.
+ samewith($path.absolute, :$skip-pager, :!try-resolving);
+}
+
+sub rakuman-resolve (
+ #| The name of the module that needs to be resolved to its file on disk.
+ Str:D $module,
+ --> IO::Path
+) is export {
+ my $file = rakuman-list-installed-compunits(){$module};
+
+ return IO::Path unless $file;
+
+ $*REPO
+ .repo-chain
+ .grep(*.?prefix.?e)
+ .map({
+ .?prefix // .path-spec.?path
+ })
+ .map(*.child("sources/$file"))
+ .grep(*.f)
+ .first
+}
+
+sub rakuman-list-installed-compunits (
+ --> Associative
+) is export {
+ # Most of this massive chain is taken with a lot of inspiration from the zef
+ # module, specifically the code that handles the locate functionality.
+ $*REPO
+ .repo-chain
+ .grep(*.?prefix.?e)
+ .map({
+ .?prefix // .path-spec.?path
+ })
+ .map(*.child('dist'))
+ .grep(*.e)
+ .map( *.IO.dir.grep(*.IO.f).Slip)
+ .map({
+ my %provides = $_.slurp.&from-json<provides>;
+
+ %provides
+ .keys
+ .map({
+ $_ => %provides{$_}.first.value<file>
+ })
+ .Slip
+ })
+ .Hash
+}
+
+=begin pod
+
+=NAME App::Rakuman
+=AUTHOR Patrick Spek <p.spek@tyil.work>
+=VERSION 0.0.0
+
+=head1 Synopsis
+
+=head1 Description
+
+=head1 Examples
+
+=head1 See also
+
+=end pod
+
+# vim: ft=perl6 noet
diff --git a/lib/App/Rakuman/Bin.pm6 b/lib/App/Rakuman/Bin.pm6
new file mode 100644
index 0000000..653e9bd
--- /dev/null
+++ b/lib/App/Rakuman/Bin.pm6
@@ -0,0 +1,40 @@
+#! /usr/bin/env false
+
+use v6.d;
+
+use App::Rakuman;
+
+unit module App::Rakuman::Bin;
+
+#| Render a Raku module's main Pod6 document.
+multi sub MAIN (
+ #| Name of a Raku module, or a path to a file.
+ Str:D $document,
+
+ #| Don't pipe the output through a pager.
+ Bool:D :$skip-pager = False,
+) is export {
+ exit rakuman(
+ $document,
+ :$skip-pager,
+ try-resolving => !($document.IO.f),
+ );
+}
+
+=begin pod
+
+=NAME App::Rakuman::Bin
+=AUTHOR Patrick Spek <p.spek@tyil.work>
+=VERSION 0.0.0
+
+=head1 Synopsis
+
+=head1 Description
+
+=head1 Examples
+
+=head1 See also
+
+=end pod
+
+# vim: ft=perl6 noet
diff --git a/lib/Pod/To/Rakuman.pm6 b/lib/Pod/To/Rakuman.pm6
new file mode 100644
index 0000000..ea579ac
--- /dev/null
+++ b/lib/Pod/To/Rakuman.pm6
@@ -0,0 +1,231 @@
+#! /usr/bin/env false
+
+use v6.d;
+
+use File::Which;
+use Pod::To::Anything::Subsets;
+use Pod::To::Anything;
+use String::Fold;
+use Terminal::ANSIColor;
+use Text::BorderedBlock;
+
+unit class Pod::To::Rakuman does Pod::To::Anything;
+
+my @footnotes;
+my $tab-size = %*ENV<TAB_SIZE>.?Int // 8;
+
+multi method render (Pod::Block::Code:D $pod --> Str) {
+ my $block = Text::BorderedBlock.new;
+ my $body;
+
+ if ($pod.config<lang> && %*ENV<RAKUMAN_PYGMENTIZE> // '' ne '0' && which('pygmentize')) {
+ my @cmd = «
+ pygmentize
+ -s
+ -l "{$pod.config<lang>}"
+ »;
+
+ my $pygmentize = run « pygmentize », :in, :out;
+
+ $pygmentize.in.say($pod.contents.join(''));
+ $pygmentize.in.close;
+
+ $body = $pygmentize.out.slurp(:close);
+ }
+
+ if (!$body) {
+ $body = $pod.contents.join('');
+ }
+
+ self.indentify(
+ $block.render(
+ $body,
+ :header($pod.config<name> // ''),
+ ),
+ :!fold
+ ) ~ "\n\n"
+}
+
+multi method render (Pod::Block::Declarator:D $pod --> Str) { self.traverse($pod) }
+
+multi method render (Pod::Block::Named::Author:D $pod --> Str) {
+ self.colorize('bold', 'Author')
+ ~ "\n"
+ ~ self.indentify(self.unpod($pod))
+ ~ "\n\n"
+}
+
+multi method render (Pod::Block::Named::Name:D $pod --> Str) {
+ self.colorize('bold', 'Name')
+ ~ "\n"
+ ~ self.indentify(self.unpod($pod))
+ ~ "\n\n"
+}
+
+multi method render (Pod::Block::Named::Subtitle:D $pod --> Str) { self.traverse($pod) }
+multi method render (Pod::Block::Named::Title:D $pod --> Str) { self.traverse($pod) }
+
+multi method render (Pod::Block::Named::Version:D $pod --> Str) {
+ self.colorize('bold', 'Version')
+ ~ "\n"
+ ~ self.indentify(self.unpod($pod))
+ ~ "\n\n"
+}
+
+multi method render (Pod::Block::Named::Pod:D $document --> Str) {
+ @footnotes = ();
+
+ my $body = self.traverse($document);
+
+ if (@footnotes) {
+ $body ~= "\n\n"
+ ~ '═' x 25;
+
+ for @footnotes.kv -> $index, $note {
+ $body ~= "\n"
+ ~ self.indentify(self.superscript-digits($index + 1), 0)
+ ~ ' '
+ ~ $note
+ }
+ }
+
+ $body
+}
+
+multi method render (Pod::Block::Para:D $pod --> Str) {
+ self.indentify(self.traverse($pod)) ~ "\n\n"
+}
+
+multi method render (Pod::Block::Named:D $pod --> Str) {
+ self.colorize('bold', $pod.name)
+ ~ "\n"
+ ~ self.indentify(self.traverse($pod))
+ ~ "\n\n"
+}
+
+multi method render (Pod::Defn:D $pod --> Str) {
+ color('italic')
+ ~ self.indentify($pod.term)
+ ~ color('reset')
+ ~ "\n"
+ ~ self.indentify(self.traverse($pod), 2)
+ ~ "\n\n"
+}
+
+multi method render (Pod::Block::Table:D $pod --> Str) { self.traverse($pod) }
+
+multi method render (Pod::FormattingCode::B:D $pod --> Str) {
+ color('bold') ~ self.traverse($pod) ~ color('reset')
+}
+
+multi method render (Pod::FormattingCode::C:D $pod --> Str) {
+ self.traverse($pod)
+}
+
+multi method render (Pod::FormattingCode::E:D $pod --> Str) { self.traverse($pod) }
+
+multi method render (Pod::FormattingCode::I:D $pod --> Str) {
+ color('italic') ~ self.traverse($pod) ~ color('reset')
+}
+
+multi method render (Pod::FormattingCode::K:D $pod --> Str) { self.traverse($pod) }
+
+multi method render (Pod::FormattingCode::L:D $pod --> Str) {
+ @footnotes
+ .append($pod.meta.map({
+ $_ ~~ Str ?? $_ !! self.traverse($_)
+ }));
+
+ color('underline blue')
+ ~ self.traverse($pod)
+ ~ color('reset')
+ ~ self.superscript-digits(@footnotes.elems)
+}
+
+multi method render (Pod::FormattingCode::N:D $pod --> Str) {
+ @footnotes.append(self.traverse($pod));
+
+ self.superscript-digits(@footnotes.elems);
+
+ ''
+}
+
+multi method render (Pod::FormattingCode::P:D $pod --> Str) { self.traverse($pod) }
+multi method render (Pod::FormattingCode::R:D $pod --> Str) { self.traverse($pod) }
+multi method render (Pod::FormattingCode::T:D $pod --> Str) { self.traverse($pod) }
+
+multi method render (Pod::FormattingCode::U:D $pod --> Str) {
+ color('underline') ~ self.traverse($pod) ~ color('reset')
+}
+
+multi method render (Pod::FormattingCode::V:D $pod --> Str) { self.traverse($pod) }
+multi method render (Pod::FormattingCode::X:D $pod --> Str) { self.traverse($pod) }
+
+multi method render (Pod::Heading:D $pod --> Str) {
+ self.colorize('bold', self.unpod($pod)) ~ "\n"
+}
+
+multi method render (Pod::Item:D $pod --> Str) {
+ my $indent-size = $tab-size * ($pod.level - 1);
+ my ($first, @rest) = self
+ .indentify('- ' ~ self.traverse($pod), $pod.level)
+ .lines
+ ;
+
+ $first ~ "\n" ~ @rest».indent(2).join("\n") ~ (@rest ?? "\n" !! '') ~ "\n"
+}
+
+#
+# Helper methods
+#
+
+method colorize (
+ Str:D $definition,
+ Str:D $content,
+ --> Str
+) {
+ color($definition) ~ $content ~ color('reset')
+}
+
+method indentify (
+ Str:D $prose is copy,
+ Int:D $levels = 1,
+ Bool:D :$fold = True,
+ --> Str
+) {
+ my $size = $levels * $tab-size;
+
+ if ($fold) {
+ $prose .= &fold(:width(79 - $size));
+ }
+
+ $prose.lines».indent($size).join("\n")
+}
+
+method superscript-digits (
+ Str() $prose,
+ --> Str
+) {
+ $prose
+ .uninames
+ .map(*.subst(/^DIGIT/, 'SUPERSCRIPT').uniparse)
+ .join
+}
+
+=begin pod
+
+=NAME Pod::To::Rakuman
+=AUTHOR Patrick Spek <p.spek@tyil.work>
+=VERSION 0.0.0
+
+=head1 Synopsis
+
+=head1 Description
+
+=head1 Examples
+
+=head1 See also
+
+=end pod
+
+# vim: ft=perl6 noet