Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add Str.indent(), run S32-str/indent.t

Original version from rakudo++'s ng branch.
  • Loading branch information...
commit b68fd9b4949dc077d733dc6d6f0b781bfb7d53a1 1 parent c8eeefc
@coke coke authored
Showing with 75 additions and 0 deletions.
  1. +74 −0 lib/CORE.setting
  2. +1 −0  t/spectest.data
View
74 lib/CORE.setting
@@ -681,6 +681,80 @@ my class Str is Cool {
[box Bool (bool 1)]
)
} }
+
+ # TODO: Switch to a multi once where is working.
+ method indent($steps) {
+ my $TABSTOP = CALLER::<$?TABSTOP> // 8;
+
+ if $steps~~Int && $steps == 0 {
+ # Zero indent does nothing
+ return self;
+ } elsif $steps~~Int && $steps > 0 {
+ # Positive indent does indent
+
+ # We want to keep trailing \n so we have to .comb explicitly instead of .lines
+ return self.comb(/:r ^^ \N* \n?/).map({
+ given $_ {
+ # Use the existing space character if they're all the same
+ # (but tabs are done slightly differently)
+ when /^(\t+) ([ \S .* | $ ])/ {
+ $0 ~ "\t" x ($steps div $TABSTOP) ~
+ ' ' x ($steps mod $TABSTOP) ~ $1
+ }
+ when /^(\h) $0* [ \S | $ ]/ {
+ $0 x $steps ~ $_
+ }
+
+ # Otherwise we just insert spaces after the existing leading space
+ default {
+ ($_ ~~ /^(\h*) (.*)$/).join(' ' x $steps)
+ }
+ }
+ }).join;
+ } else {
+ # Negative values and Whatever-* do outdent
+ # Loop through all lines to get as much info out of them as possible
+ my @lines = self.comb(/:r ^^ \N* \n?/).map({
+ # Split the line into indent and content
+ my ($indent, $rest) = @($_ ~~ /^(\h*) (.*)$/);
+
+ # Split the indent into characters and annotate them
+ # with their visual size
+ my $indent-size = 0;
+ my @indent-chars = $indent.comb.map(-> $char {
+ my $width = $char eq "\t"
+ ?? $TABSTOP - ($indent-size mod $TABSTOP)
+ !! 1;
+ $indent-size += $width;
+ $char => $width;
+ });
+
+ { :$indent-size, :@indent-chars, :$rest };
+ });
+
+ # Figure out the amount * should outdent by, we also use this for warnings
+ my $common-prefix = [min] @lines.map({ $_<indent-size> });
+
+ # Set the actual outdent amount here
+ my Int $outdent = $steps ~~ Whatever ?? $common-prefix
+ !! -$steps;
+ warn sprintf('Asked to remove %d spaces, ' ~
+ 'but the shortest indent is %d spaces',
+ $outdent, $common-prefix) if $outdent > $common-prefix;
+
+ # Work backwards from the right end of the indent whitespace, removing
+ # array elements up to # (or over, in the case of tab-explosion)
+ # the specified outdent amount.
+ @lines.map({
+ my $pos = 0;
+ while $_<indent-chars> and $pos < $outdent {
+ $pos += $_<indent-chars>.pop.value;
+ }
+ $_<indent-chars>».key.join ~ ' ' x ($pos - $outdent) ~ $_<rest>;
+ }).join;
+ }
+ }
+
method gist() { defined(self) ?? self !! nextsame }
method Numeric () { ::Niecza::NumSyntax.str2num(~self) }
method perl() {
View
1  t/spectest.data
@@ -413,6 +413,7 @@ S32-str/chomp.t
S32-str/chop.t
S32-str/comb.t
S32-str/flip.t
+S32-str/indent.t
S32-str/index.t
S32-str/lc.t
S32-str/lcfirst.t
Please sign in to comment.
Something went wrong with that request. Please try again.