#!/usr/local/bin/perl
##############################################################################
#  xwe  -  A wafe editor
#
#  It is configured (colors, keyboard bindings, etc) through the
#  .waferc file.
#
#  Version 0.29
#  1992-02-12
#
#  This editor is in the public domain.
#
#  Dov Grobgeld                        Gustaf Neumann
#  Department of Chemical Physics      Wirtschaftsuniversitaet Wien
#  The Weizmann Inst. of Science       Abteilung fuer Wirtschaftsinformatik
#  Rehovot 76100, Israel               Augasse 2-6, A-1090 Vienna, Austria
#  dov@menora.weizmann.ac.il           neumann@wu-wien.ac.at
#
##############################################################################

$WafeLib = $ENV{'WAFELIB'} || "/usr/lib/X11/wafe";
require "$WafeLib/perl/wafe.pl";
require "wafe_pcmd.pl";

require "$ENV{HOME}/.xwerc" if -f "$ENV{HOME}/.xwerc";
require ".xwerc" if -f ".xwerc";

$fn=shift || (print "no file name specified!\n") && &Xui("quit");

$textWidth=660 unless $textWidth;

#############################################################################
# Set defaults
#############################################################################
$xdviOptions="-expert -hush -geometry 720x400 -margins 1.5 -s 2 " .
             "-p 250 -bg snow" unless $xdviOptions;
$texHeader="\\documentstyle\{article\}\n" unless $texHeader;
$texTrailer="\\end{document}\n" unless $texTrailer;

# Keybindings

@xweTextActions= (
    "<Key>Escape:       exec( cmdl_on ) ",
    "$meta<Key>x:       exec( cmdl_on ) ",
#    "Ctrl<Key>x,<Key>s: exec( echo save ) ",
#    "Ctrl<Key>x,<Key>c: exec( echo file ) ",
    ) unless (@xweTextActions);

@xweCommandActions = (
    "Ctrl<Key>y:     exec( sV command string {} ) ",
    "Ctrl<Key>u:     exec( echo command:undo ) ",
    "<Key>Up:        exec( echo command:prevCommand ) ",
    "<Key>Down:      exec( echo command:nextCommand ) ",
    "<Key>Escape:    exec( cmdl_off ) ",
    "$meta<Key>x:     exec( cmdl_off ) ",
    ) unless (@xweCommandActions);

##########################################################################
# Build the widget structure.
##########################################################################

&wafe'setResources("",%textResources);

&UI(<<"End of Wafe");
    sV topLevel title xwe:$fn

    # Procedures

    proc simpleButtonCB {name father resources} {\\
       eval command \$name \$father \$resources $buttonAtts \\
       callback {{echo %w}}}

    proc simpleButton {name father resources} {\\
       eval command \$name \$father \$resources $buttonAtts}

    proc cmdl_on  {} {setKeyboardFocus form command;sV command $highLight; \\
                      textDisplayCaret command true }
    proc cmdl_off {} {setKeyboardFocus form edit;sV command $backGround; \\
                      textDisplayCaret command false }

    # widgets

    paned form topLevel $backGround orientation vertical

    label info form label "" min 20 max 20 height 18 width $textWidth \\
        $infoColors $textFont

    asciiText edit form scrollVertical always showGrip false height 620 \\
        width $textWidth \\
        $roColors $textFont editType edit wrap line

    asciiText command form min 20 max 20 showGrip false height 20 width \\
        $textWidth $backGround $textFont editType edit

    box buttons form min 26 max 26 $backGround showGrip false
    simpleButton   abort  buttons {callback quit}
    simpleButtonCB file   buttons {}
    simpleButtonCB save   buttons {}
    simpleButton   latex  buttons {callback "echo command:latex"}
    simpleButtonCB help   buttons {}


    # Help widget structure

    topLevelShell helpTop topLevel title "xwe Help"
    paned helpForm helpTop $backGround
    callback helpTop popupCallback position info:30/30
    asciiText helpText helpForm \\
    	scrollVertical always showGrip false height 400 width $textWidth \\
        $roColors $textFont wrap Line type file string "$WafeLib/xwe.help" 
    box helpButtons helpForm min 26 max 26 $backGround
    command close helpButtons $buttonAtts callback {popdown helpTop}


    # Hardwired actions

    action info override { <ButtonPress> : exec( sV info label {} ) }
    action command override { <Key>Return : exec( \\
            set line "[gV command string]"; \\
            echo "command:\$line"; \\
#            cmdl_off;
        ) }
    action command override { <LeaveWindow>:  exec( cmdl_off ) }
    action command override { <EnterWindow>:  exec( cmdl_on ) }


    # Finally realize the widget structure and do some initialization

    realize
    deleteWindowProtocol quit
    cmdl_off
End of Wafe

# Check for non-existing filename

unless(-f $fn) {
    open(NEWFILE, ">$fn"); close(NEWFILE);
    &warn('Warning: New file');
}
else { &info("Loaded file $fn"); }

# Set all the softwired actions

&wafe'setWidgetToFile('edit',$fn);
&wafe'applyActions('edit', @textActions);
&wafe'applyActions('edit', @xweTextActions) if @xweTextActions;
&wafe'applyActions('command', @xweCommandActions) if @xweTextActions;

$filterTmpFile  = &wafe'tmpFile("xwefilter");
$texTmpFile     = "./xwetex$$";
$wafe'toRemove .= "$texTmpFile.dvi $texTmpFile.tex $texTmpFile.log "
                 ."$texTmpFile.aux $texTmpFile.toc ";

# Finally do event loop

while(<STDIN>) {
#    &info('');
    &Xui("asciiSave edit; quit") if /^file/;
    &Xui("asciiSave edit"),&info("File saved") if /^save/;
    &Xui("callActionProc edit {} search forward") if /^search/;
    if (/^help/) {
        &UI(<<QQ);
            popup helpTop none
            setWMProtocols helpTop WM_DELETE_WINDOW
            action helpTop override "<Message>WM_PROTOCOLS: exec(popdown helpTop)"
QQ
        &wafe'applyActions(helpText,  @textActions);
    }
    if (/^match:/) {
        if ($'+0) {
            &UI("callActionProc edit {} redraw-display;") if $redrawAfterFind;
            &info;
        } else { &warn("No match!"); };
    }
    if (/^command:/) {
        chop($_=$');
        push(@commandStack, $_) unless $_ eq $commandStack[$#commandStack];

        if (/^prevCommand|nextCommand/) { # command line history
            pop(@commandStack); # don't save on the command stack
            local($dir) = (/^p/ ? -1 : +1);
            $commandCounter += $dir;
            if ($commandCounter > $#commandStack || $commandCounter < 0) {
                &warn(); # ring the bell
                $commandCounter -= $dir;
            }
            else {
                # Hide the caret when changing the command string. 
                # Otherwise small dirty dots are left in the command window.
                &UI("textDisplayCaret command false; " .
                    "sV command string " .
                    &tclQuote($commandStack[$commandCounter]) . ";" .
                    "callActionProc command {} end-of-line;" .
                    "textDisplayCaret command true");
            }
        }
        else {
            $commandCounter= $#commandStack;
        }

        if (/^prevCommand|^nextCommand/) {} # swallow error message
        elsif (/^again/) { # Repeat the last command
            &UI('set line "[gV command string]"; echo "command:$line"');
            pop(@commandStack); # don't save on the command stack
        }
        elsif (/^\/|^\?/) { # search forwards or backwards
            local($string) = $';
            local($dir) = $& eq '?' ? 'left' : 'right';
            &Xui("echo match: [searchText edit $dir ".&tclQuote($string)."]");
        }
        elsif (/^\|/) { # Filter
            local($cmd)= /\|(.+)/;
            local($replace);

            open(PIPE, "|$cmd > $filterTmpFile");
            $undo=&getSelection(edit);
            print PIPE $undo;
            close(PIPE);
            open(IN, "<$filterTmpFile");
            $replace= join("",<IN>);
            close(IN);
            &setSelection(edit, $replace);
        }
        elsif (/^>\s*(.*)/) { # Save to file
            open(OUT, ">$1"); print OUT &getSelection(edit); close(OUT);
        }
        elsif (/^s\W/) {
            local($command)=$_;
            local($_,$n, $replace);

            $undo=&getSelection(edit);
            @lines=split(/\n/,$undo,99999999);
            eval "grep(\$n+= $command, \@lines)";
            if ($@) {
                &warn("Syntax error in statement!");
            }
            elsif ($n==0) {
                &warn("No matches found!");
            } else {
                &info("$n replacements carried out");
                &setSelection(edit, join("\n", @lines));
            }

        }
        elsif (/p\|/) {
            local($command)=$';
            local($_,$n, $replace);

            $undo=&getSelection(edit);
            @lines=split(/\n/,$undo,99999999);
            eval "foreach (\@lines) {$command;}";
            if ($@) {
                &warn("Syntax error in statement!");
            } else {
                &info("piping done...");
                &setSelection(edit, join("\n", @lines));
                &Xui("callActionProc edit {} redraw-display");
            }

        }
        elsif (/undo/) {
            &setSelection(edit,$undo);
            &info("Undoing replace");
        }
        elsif (/^g\s+/) { # Jump to a specific line
            $line=$'-1;
            &UI(<<"QQ");
                set ip [textSourceScan edit 0 EOL right $line true]
                textSetInsertionPoint edit \$ip
                callActionProc edit {} redraw-display
QQ
        }
        elsif (/^latex/) {
            # Construct texheader and footer files if they don't exist
            unless (-f "texheader.tex") {
                open(TEX,">texheader.tex");
                print TEX $texHeader;
                close(TEX);
            }
            unless (-f "textrailer.tex") {
                open(TEX,">textrailer.tex");
                print TEX $texTrailer;
                close(TEX);
            }
            local($selection)= &getSelection(edit);
            if ($selection) {
                &info("LaTeXing selection");
                open(TEX, ">$texTmpFile.tex");
                print TEX '\nonstopmode\input texheader ',
                       "\n$selection\n\\input textrailer\n";
                close(TEX);
            } else {
                &info("LaTeXing file");
                &widgetContent("$texTmpFile.tex",'edit');
            }
            system "latex $texTmpFile > /dev/null; " .
                   "xdvi $xdviOptions $texTmpFile.dvi > /dev/null &";
        }
        else {
            &warn("Unknown command $_!");
        }
    }
    elsif (/^pcmd:/) {
        &pcmd($');
    }
}
