aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xcolorize-amsb284
-rw-r--r--colorize-amsb.1100
-rw-r--r--colorize-amsb.rst39
3 files changed, 423 insertions, 0 deletions
diff --git a/colorize-amsb b/colorize-amsb
new file mode 100755
index 0000000..4d6c616
--- /dev/null
+++ b/colorize-amsb
@@ -0,0 +1,284 @@
+#!/usr/bin/perl -w
+
+# colorize output from listbas... *after* it's been converted to utf8
+# with a8cat, including ANSI codes for reverse/normal video.
+
+($SELF = $0) =~ s,.*/,,;
+
+%colornames = (
+ none => 0,
+ red => 1,
+ green => 2,
+ yellow => 3,
+ blue => 4,
+ purple => 5,
+ cyan => 6,
+);
+
+%colors = (
+ numbers => 'red',
+ commands => 'yellow',
+ functions => 'purple',
+ linenumbers => 'cyan',
+ comments => 'blue',
+ variables => 'none',
+ operators => 'green',
+ strings => 'red',
+);
+
+@commands = qw/
+ END FOR NEXT READ DATA RESTORE LINE INPUT DEFSTR DEFINT DEFDBL DEFSNG
+ OPTION DIM COMMON DEF LET RANDOMIZE GOTO GOSUB RETURN GO RUN IF
+ ELSE THEN STOP CONT RESUME ERROR ON AFTER POKE WAIT MOVE LOAD SAVE
+ VERIFY MERGE PRINT PRINT LIST AUTO DEL TRON TROFF RENUM OPEN CLOSE
+ GET PUT NOTE LOCK UNLOCK KILL NAME GRAPHICS COLOR PLOT FILL SETCOLOR
+ SOUND CLS DOS CLEAR NEW CLOAD CSAVE BASE TO SUB NOT STEP ALL USING
+ RESERVE UPDATE OUTPUT APPEND AT PLM0 PLM2 PLM1 CHR0 CHR1 CHR2 AND
+ OR XOR
+/;
+
+@functions = qw/
+ TAB SPC AT SGN INT ABS FRE POS SQR LOG EXP COS SIN TAN ATN PEEK LEN STR
+ VAL ASC CHR STATUS EOF LEFT RIGHT MID INSTR STRING VARPTR USR SCRN RND
+ TIME INKEY ERR ERL STACK
+/;
+
+$cmdhash{$_}++ for @commands;
+$funchash{$_}++ for @functions;
+
+sub conf_file_name {
+ my $home = $ENV{HOME};
+ if(!defined $home) {
+ warn "$SELF: HOME not set in environment, not reading config file\n";
+ return undef;
+ }
+ return $home . '/.colorize-amsb.conf';
+}
+
+sub read_config {
+ my $file = conf_file_name();
+ return 1 if !defined $file; # caller won't create
+ open my $fh, '<', $file or return 0; # not found, caller will create
+
+ while(<$fh>) {
+ chomp;
+ s/#.*//;
+ next if /^\s*$/;
+ s/^\s*//;
+ s/\s*$//;
+ $_ = lc $_;
+ if(/^([a-z]+)[^a-z]+([a-z]+)*$/) {
+ my($k, $v) = ($1, $2);
+ if(!defined $colors{$k}) {
+ warn "$SELF: $file:$.: unknown color type '$k', ignoring\n";
+ } elsif(!defined $colornames{$v}) {
+ warn "$SELF: $file:$.: unknown color name '$v', ignoring\n";
+ } else {
+ $colors{$k} = $v;
+ }
+ } else {
+ warn "$SELF: $file:$.: malformed line, skipping\n";
+ }
+ }
+
+ close $fh;
+}
+
+sub create_config {
+ my $file = conf_file_name();
+ return unless defined $file;
+ open my $fh, '>', $file or do {
+ warn "$SELF: can't create $file: $!\n";
+ return;
+ };
+
+ my $types = join(" ", sort keys %colors);
+ my $names = join(" ", sort keys %colornames);
+
+ print $fh <<EOF;
+# colorize-amsb.conf
+
+# lines with # are comments. blank lines are ignored.
+
+# each line is "type = color", where valid types are:
+# $types
+# and valid colors are:
+# $names
+
+EOF
+
+ for(sort keys %colors) {
+ print $fh '#' . $_ . ' = ' . $colors{$_} . "\n";
+ }
+
+ close $fh;
+}
+
+sub is_cmd {
+ return $cmdhash{$_[0]};
+}
+
+sub is_func {
+ return $funchash{$_[0]};
+}
+
+sub is_punct {
+ for($_[0]) {
+ return 0 if length > 1;
+ return 0 if /[\sA-Za-z0-9]/;
+ }
+ return 1;
+}
+
+sub is_varname {
+ return $_[0] =~ /^[A-Z]/;
+}
+
+sub start_color {
+ my $color = shift;
+ my $colortype = $colors{$color} || die "invalid color type $color\n";
+ my $colornum = $colornames{$colortype};
+ die "invalid color name $color\n" unless defined $colornum;
+ if($colornum) {
+ print "\x1b[3" . $colornum . "m";
+ }
+}
+
+sub end_color {
+ print "\x1b[0m";
+}
+
+sub colorize {
+ my $color = shift;
+ my $text = shift;
+ #warn "color $color, text '$text'\n";
+ start_color($color) if $color;
+ print $text;
+ end_color if $color;
+}
+
+sub colorize_line {
+ my $line = shift;
+
+ # skip initial blank line (or really any blank lines)
+ return unless length $line;
+
+ # split on non-word characters, capturing the delimiters.
+ # spliting this: 10 PRINT "HELLO":A=1.0E+10:END
+ # ...gives this set of tokens:
+ # 10
+ # <space>
+ # PRINT
+ # <space>
+ # "
+ # HELLO
+ # "
+ # :
+ # 1
+ # .
+ # 0E
+ # +
+ # 10
+ # :
+ # END
+
+ @toks = (split(/(\W)/, $line));
+
+ # special case the line number
+ my $tok = shift @toks;
+ if($tok =~ /^\d+/) {
+ colorize('linenumbers', $tok);
+ } else {
+ die "$SELF: no line number at line $., not LISTed AMSB?\n";
+ }
+
+ my $lasttok = '';
+ my $lastcolor = 0;
+ my $in_comment = 0;
+ my $in_string = 0;
+
+ # iterate over the rest of the tokens. kinda hairy, sorry.
+ for my $tok (@toks) {
+ my $color = 0;
+
+ if($in_comment || $in_string) {
+ $color = 0;
+ if($in_string && $tok eq '"') {
+ $in_string = 0;
+ $color = 'operators';
+ }
+ } elsif($tok =~ /^REM|!|'/) {
+ start_color('comments'); # rest of line
+ $in_comment = 1;
+ } elsif($tok eq '"') {
+ $color = 'operators';
+ $in_string = 1;
+ } elsif($tok eq '#') {
+ if($lastcolor eq 'variables') {
+ # double-precision variable
+ $color = 'variables';
+ } else {
+ # OPEN #, PRINT #, CLOSE #, etc
+ $color = 'operators';
+ }
+ } elsif($tok eq '%') {
+ # integer variable
+ $color = 'variables';
+ } elsif($tok eq '#' && $lastcolor eq 'variables') {
+ # double-precision variable
+ $color = 'variables';
+ } elsif($tok eq '$') {
+ # $ takes either the functions or variables color
+ $color = $lastcolor;
+ } elsif($tok eq '.') {
+ # decimal point only appears in a number
+ $color = 'numbers';
+ } elsif(($tok eq '-' || $tok eq '+') && $lasttok =~ /^\d+E$/) {
+ # scientific notation (entire number is the same color)
+ $color = 'numbers';
+ } elsif($tok eq '&') {
+ # hex constant operator
+ $color = 'numbers';
+ } elsif($lasttok eq '&') {
+ # hex constant argument
+ $color = 'numbers';
+ } elsif(is_cmd($tok)) {
+ $color = 'commands';
+ } elsif(is_func($tok)) {
+ $color = 'functions';
+ } elsif(is_punct($tok)) {
+ $color = 'operators';
+ } elsif(is_varname($tok)) {
+ $color = 'variables';
+ } else {
+ $color = 'numbers';
+ }
+
+ # if $color == 0, colorize() just prints the token without escape codes.
+ colorize($color, $tok);
+
+ # if we just started a string, set the strings color.
+ if($tok eq '"' && $in_string) {
+ start_color('strings');
+ }
+ $lastcolor = $color;
+ $lasttok = $tok;
+ }
+
+ # don't leave the text color enabled at the end of the line.
+ end_color() if $in_comment || $in_string;
+}
+
+# main()
+binmode(STDIN, ":utf8");
+binmode(STDOUT, ":utf8");
+
+if(!read_config()) {
+ create_config();
+}
+
+while(<>) {
+ chomp;
+ colorize_line($_);
+ print "\n";
+}
diff --git a/colorize-amsb.1 b/colorize-amsb.1
new file mode 100644
index 0000000..f18143d
--- /dev/null
+++ b/colorize-amsb.1
@@ -0,0 +1,100 @@
+.\" Man page generated from reStructuredText.
+.
+.
+.nr rst2man-indent-level 0
+.
+.de1 rstReportMargin
+\\$1 \\n[an-margin]
+level \\n[rst2man-indent-level]
+level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
+-
+\\n[rst2man-indent0]
+\\n[rst2man-indent1]
+\\n[rst2man-indent2]
+..
+.de1 INDENT
+.\" .rstReportMargin pre:
+. RS \\$1
+. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
+. nr rst2man-indent-level +1
+.\" .rstReportMargin post:
+..
+.de UNINDENT
+. RE
+.\" indent \\n[an-margin]
+.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.nr rst2man-indent-level -1
+.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
+..
+.TH "COLORIZE-AMSB" 1 "2025-03-16" "0.2.2" "Urchlay's Atari 8-bit Tools"
+.SH NAME
+colorize-amsb \- color syntax highlighting for detokenized Atari MS BASIC
+.SH SYNOPSIS
+.sp
+\fBcolorize\-amsb\fP [\fBfile\fP]
+.SH DESCRIPTION
+.sp
+\fBcolorize\-amsb\fP is a filter that postprocesses the LISTed output
+of \fBlistamsb\fP, after it has been piped through \fBa8cat\fP\&. Normally,
+there\(aqs no need to run \fBcolorize\-amsb\fP explicitly, as it\(aqs called by
+\fBlistamsb\fP automatically.
+.sp
+\fBcolorize\-amsb\fP takes no options.
+.SH CONFIGURATION
+.sp
+The colors are controlled by the config file, \fB~/.colorize\-amsb.conf\fP\&.
+.sp
+If the file doesn\(aqt exist, \fBcolorize\-amsb\fP creates it, with all
+options commented out. See the comments in the file for the syntax.
+.SH EXIT STATUS
+.sp
+0 for success, non\-zero for any error. Error messages are printed to \fBstderr\fP\&.
+.SH COPYRIGHT
+.sp
+WTFPL. See \fI\%http://www.wtfpl.net/txt/copying/\fP for details.
+.SH AUTHOR
+.INDENT 0.0
+.IP B. 3
+Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\&.
+.UNINDENT
+.SH SEE ALSO
+.sp
+\fBa8cat\fP(1),
+\fBa8eol\fP(1),
+\fBa8xd\fP(1),
+\fBatr2xfd\fP(1),
+\fBatrsize\fP(1),
+\fBaxe\fP(1),
+\fBbas2aplus\fP(1),
+\fBblob2c\fP(1),
+\fBblob2xex\fP(1),
+\fBcart2xex\fP(1),
+\fBcxrefbas\fP(1),
+\fBdasm2atasm\fP(1),
+\fBdiffbas\fP(1),
+\fBdumpbas\fP(1),
+\fBf2toxex\fP(1),
+\fBfenders\fP(1),
+\fBlistbas\fP(1),
+\fBlistamsb\fP(1),
+\fBprotbas\fP(1),
+\fBrenumbas\fP(1),
+\fBrom2cart\fP(1),
+\fBunmac65\fP(1),
+\fBunprotbas\fP(1),
+\fBvxrefbas\fP(1),
+\fBwhichbas\fP(1),
+\fBxex1to2\fP(1),
+\fBxexamine\fP(1),
+\fBxexcat\fP(1),
+\fBxexsplit\fP(1),
+\fBxfd2atr\fP(1),
+\fBxex\fP(5),
+\fBatascii\fP(7),
+\fBfauxtari\fP(7).
+.sp
+Any good Atari 8\-bit book: \fIDe Re Atari\fP, \fIThe Atari BASIC Reference
+Manual\fP, the \fIOS Users\(aq Guide\fP, \fIMapping the Atari\fP, etc.
+.\" Generated by docutils manpage writer.
+.
diff --git a/colorize-amsb.rst b/colorize-amsb.rst
new file mode 100644
index 0000000..b680b31
--- /dev/null
+++ b/colorize-amsb.rst
@@ -0,0 +1,39 @@
+=============
+colorize-amsb
+=============
+
+--------------------------------------------------------
+color syntax highlighting for detokenized Atari MS BASIC
+--------------------------------------------------------
+
+.. include:: manhdr.rst
+
+SYNOPSIS
+========
+
+**colorize-amsb** [**file**]
+
+DESCRIPTION
+===========
+
+**colorize-amsb** is a filter that postprocesses the LISTed output
+of **listamsb**, after it has been piped through **a8cat**. Normally,
+there's no need to run **colorize-amsb** explicitly, as it's called by
+**listamsb** automatically.
+
+**colorize-amsb** takes no options.
+
+CONFIGURATION
+=============
+
+The colors are controlled by the config file, **~/.colorize-amsb.conf**.
+
+If the file doesn't exist, **colorize-amsb** creates it, with all
+options commented out. See the comments in the file for the syntax.
+
+EXIT STATUS
+===========
+
+0 for success, non-zero for any error. Error messages are printed to **stderr**.
+
+.. include:: manftr.rst