package ActiveState::Indenter; use strict; require IO::Handle; # ensure print method works on real file handles sub new { my $class = shift; my $fh = shift; bless { fh => $fh, col => 0, line => 1, indent => 4, width => 70, tab => [], }, $class; } sub _print { my $self = shift; my $str = shift; my $fh = $self->{fh}; return $fh->print($str) if $str eq "\n"; my $indent_needed = $self->indent - $self->{col}; if ($indent_needed > 0) { $fh->print(" " x $indent_needed); $self->{col} += $indent_needed; } $fh->print($str); } sub handle { my $self = shift; $self->{fh}; } sub line_width { my $self = shift; my $old = $self->{width}; $self->{width} = shift if @_; $old; } sub indent_offset { my $self = shift; my $old = $self->{indent}; $self->{indent} = shift if @_; $old; } sub line { my $self = shift; my $old = $self->{line}; $self->{line} = shift if @_; $old; } sub print { my $self = shift; my $fh = $self->{fh}; my $str = join(" ", @_); my $indent = $self->indent; while ((my $nl = index($str, "\n")) >= 0) { $self->_print(substr($str, 0, $nl+1, "")); $self->{line}++; $self->{col} = 0; } return unless length($str); $self->_print($str); $self->{col} += length($str); } sub soft_space { my $self = shift; $self->print($self->{col} > $self->{width} ? "\n" : " "); } sub indent { my $self = shift; return @{$self->{tab}} ? $self->{tab}[-1] : 0; } sub over { my $self = shift; push(@{$self->{tab}}, $self->indent + (shift || $self->{indent})); } sub over_cur { my $self = shift; push(@{$self->{tab}}, $self->column); } sub over_abs { my $self = shift; push(@{$self->{tab}}, shift || 0); } sub back { my $self = shift; die "Underflow" unless @{$self->{tab}}; pop(@{$self->{tab}}); } sub column { my $self = shift; $self->{col}; } sub depth { my $self = shift; return scalar(@{$self->{tab}}); } 1; __END__ =head1 NAME ActiveState::Indenter - Keep track of indentation levels =head1 SYNOPSIS use ActiveState::Indenter; my $fh = ActiveState::Indenter->new(*STDOUT); $fh->print("if (foo()) {\n") $fh->over; $fh->print("# do something\n"); $fh->back; $fh->print("}\n"); =head1 DESCRIPTION The ActiveState::Indenter works like an output file handle but will insert whitespace in the printed stream reflecting the current indentation level. It is useful for printing out nicely formatted programs. The following methods are available: =over =item $fh = ActiveState::Indenter->new( $filehandle ) The object constructor takes a file handle as argument. It will create a new indenter object that prints to the given file handle. The $filehandle can actually be any object that implement a print() method. =item $fh->handle Returns back the filehandle passed to the constructor. =item $fh->line_width =item $fh->line_width( $new_width ) This get/set the current line width. The line width is used by the soft_space() method. The default is 70. =item $fh->indent_offset =item $fh->indent_offset( $new_offset ) This get/set the standard indentation offset. The default is 4. =item $fh->print( $string ) The print() will print the string given as argument to the wrapped file handle but with suitable additional leading space added. The indenter object will never buffer output, so all content of the string will have reached the file when print returns. =item $fh->soft_space This will print a space character " " if there is more room on the line, or a newline otherwise. =item $col = $fh->indent This returns the current indentation column. =item $fh->over =item $fh->over( $offset ) This increase the indentation column with the given amount. Without argument the standard amount is used. =item $fh->over_cur This sets the indentation column the same as the current column. =item $fh->over_abs( $col ) This set the indentation column to the number given. =item $fh->back Returns to the previous indentation column. =item $col = $fh->column Returns the current column position. =item $line = $fh->line =item $fh->line( $new_line ) This get/set the current line number. =item $n = $fh->depth Returns the current indentation depth. =head1 COPYRIGHT Copyright (C) 2003 ActiveState Corp. All rights reserved. =cut