/*
$Id: spell.the,v 1.1 2001/01/04 09:42:04 mark Exp $
*/
/***********************************************************************/
/* Description: REXX macro to check spelling of words in a target.     */
/* Syntax:      spell target                                           */
/* Notes:       This macro spells words in the lines specified in the  */
/*              target.                                                */
/*              Full XEDIT/KEDIT/THE targets are supported include WORD*/
/*              (WORD option not yet supported)                        */
/*              This macro will only work with International Ispell    */
/*              v 3.1 or above.                                        */
/***********************************************************************/
Trace o
If batch() Then
   Do
     'emsg This macro cannot be run in batch'
     Exit 1
   End
arg1 = Arg(1)
noargs = Arg()
'preserve'
time_to_quit = 'NO'
spell_command = 'ispell -a'
no_match_line = "'A' to add, 'E' to edit, 'I' to ignore or 'Q' to quit."
If noargs = 0 Then arg1 = '1'               /* no args - assume 1 line */
forward = 1                  /* assume direction is forward by default */
'EXTRACT /LINE/SIZE/STAY/FTYPE/FNAME/CURLINE/RESERVED */BLOCK/ZONE/'    /* get various stuff */
reserved_start = curline.2
current_line = line.1                   /* save current line for later */
left_col = zone.1
right_col = zone.2
If arg1 = 'word' | arg1 = 'WORD' Then Call spell_word
Else Call spell_target

/* put things back the way they were */
'reserved * off'
Do i = 1 To reserved.0      /* restore any reserved lines as they were */
  'reserved' reserved.i
End
'reset block'
'zone' zone.1 zone.2
'restore'
Return

/*---------------------------------------------------------------------*/
spell_target:
/*---------------------------------------------------------------------*/
reply = valid_target(arg1)
If reply = 'ERROR' Then
   Do
     'EMSG Error: 17 Invalid target' arg1
     'restore'
     Exit
   End
If reply = 'NOTFOUND' Then
   Do
     'EMSG Error: 17 Target not found' arg1
     'restore'
     Exit
   End
If Translate(arg1) = 'BLOCK' Then
   Do
     'EXTRACT /BLOCK/'
     If block.1 \= 'LINE' Then
        Do
          left_col = block.3
          right_col = block.5
        End
   End
start_line = Word(reply,1)                        /* get starting line */
nolines = Word(reply,2)                         /* get number of lines */
If nolines < 0 Then Do                /* if target before current line */
   forward = 0                    /* indicate direction to be backward */
   nolines = nolines * -1                     /* make nolines positive */
End
'cursor cmdline'
':'||start_line                                    /* go to first line */
totlines = 0                             /* reset changed line counter */
Do Forever                              /* for each line to target ... */
   If nolines = 0 Then Leave
   respell_current_line = 'NO'
   'EXTRACT /CURLINE/TOF/EOF/LINE/'       /* get current line contents, etc.*/
   If tof.1 = 'ON',                    /* ignore line if on TOF or EOF */
   |  eof.1 = 'ON' Then Nop
   Else
     Do
       line = Translate(curline.3,,'`"1234567890	-=\~!@#$%^&*()_+|[]{};:,.<>/?',' ')
       wordidx = 0
       Do i = 1 To Words(line)
          word_start_col = Wordindex(line,i)
          If word_start_col >= left_col & word_start_col <= right_col Then
             Do
               wordidx = wordidx + 1
               word_in_line.wordidx = Word(line,i)
               word_start.wordidx = Wordindex(line,i)
             End
       End
       word_in_line.0 = wordidx
       word_start.0 = wordidx
       Call RunSpellCommand "word_in_line." "word_out_line." "stderr."
       Call TidyOutput
       Do i = 1 To word_out_line.0
          Parse Var word_out_line.i cmd . num . ':' wordlist
          Select
            When cmd = '*' | cmd = '+' | cmd = '-' Then Iterate
            When cmd = '#' Then Call no_match
            When cmd = '&' & num > 0 Then
                 Do
                   word_out_line.i = Translate(wordlist,' ',',')
                   Call matches
                 End
            Otherwise Nop
          End
          If time_to_quit = 'YES' Then Leave
          If respell_current_line = 'YES' Then Leave
       End
       /* display prompts etc here */
       drop word_in_line.
       drop word_out_line.
     End
   If time_to_quit = 'YES' Then Leave
   'cursor cmdline'
   If respell_current_line \= 'YES' Then
     Do
       If forward = 1 Then 'N'      /* if going forward, get next line */
       Else 'U'               /* if going backwards, get previous line */
       If rc \= 0 Then Leave                     /* shouldn't get here */
       nolines = nolines - 1
     End
End
'cursor cmdline'
If stay.1 = 'ON' Then ':'||current_line 
'msg Spelling complete'
Return                                               /* go back to THE */

/*---------------------------------------------------------------------*/
spell_word:
/*---------------------------------------------------------------------*/
Return

/*---------------------------------------------------------------------*/
no_match:
/*---------------------------------------------------------------------*/
'reserved * off'
Call HighlightWord                               /* highlight the word */
'reserved' reserved_start+1 'No suggestions for:' word_in_line.i
'reserved' reserved_start+2 no_match_line
Call ProcessResponse 'NOMATCH'
Return

/*---------------------------------------------------------------------*/
matches:
/*---------------------------------------------------------------------*/
'reserved * off'
Call HighlightWord                               /* highlight the word */
'reserved' reserved_start+1 'Suggestions for:' word_in_line.i
Do j = 1 To Min(Words(word_out_line.i),9)
   'reserved' j+1+reserved_start '  ('||j||')' Word(word_out_line.i,j)
End
'reserved' j+1+reserved_start 'Press a number,' no_match_line
Call ProcessResponse j-1
Return

/*---------------------------------------------------------------------*/
ProcessResponse:
/*---------------------------------------------------------------------*/
Parse Arg itemno .
Do Forever
   'readv KEY'
   readv.1 = Translate(readv.1)
   Select
     When readv.1 = 'A' Then
       Do
         insert.0 = 2
         insert.1 = '*' || word_in_line.i    /* add word to dictionary */
         insert.2 = '#'                             /* save dictionary */
         Call RunSpellCommand "insert." "result." "stderr."
         drop insert.
         drop result.
         Leave
       End
     When readv.1 = 'Q' Then
       Do
         time_to_quit = 'YES'
         Leave
       End
     When readv.1 = 'E' Then
       Do
         Call EditWord
         Leave
       End
     When readv.1 = 'I' Then Leave
     When Datatype(itemno) = 'NUM' & readv.1 >= 1 & readv.1 <= itemno Then
       Do
         itemno = itemno
         off = Length(Word(word_out_line.i,itemno))-Length(word_in_line.i)
         Do wordidx = i+1 To word_in_line.0
            word_start.wordidx = word_start.wordidx + off
         End
         'zone' word_start.i '*'
         'nomsg c/'||word_in_line.i||'/'||Word(word_out_line.i,readv.1)||'/'
         Leave
       End
     Otherwise 
       Do
         'emsg Invalid response'
       End
   End
End
'reserved * off'
'reset block'
'refresh'
Return

/*---------------------------------------------------------------------*/
HighlightWord:
/*---------------------------------------------------------------------*/
'reset block'
'cursor file' line.1 word_start.i + Length(word_in_line.i) -1
'mark box'
'cursor file' line.1 word_start.i
'mark box'
Return

/*---------------------------------------------------------------------*/
EditWord:
/*---------------------------------------------------------------------*/
orig_len = Length(word_in_line.i)
'readv cmdline' word_in_line.i
'zone' word_start.i '*'
'nomsg c/'||word_in_line.i||'/'||readv.1||'/'
word_in_line.i = Word(readv.1,1)
respell_current_line = 'YES'
'zone 1 *'
Return

/*---------------------------------------------------------------------*/
RunSpellCommand:
/*---------------------------------------------------------------------*/
Parse Arg instem outstem errstem .
rc = run_os(spell_command,instem,outstem,errstem)
If rc \= 0 Then
   'emsg Return code from "'||spell_command||'"' rc
If stderr.0 \= 0 Then
   Do
     Do i = 1 To stderr.0
        'emsg' stderr.i
     End
     'restore'
     Exit 1
   End
If rc \= 0 Then Exit 1
Return

/*---------------------------------------------------------------------*/
TidyOutput:
/*---------------------------------------------------------------------*/
Do m = 2 To word_out_line.0 By 2
   Queue word_out_line.m
End
numqueued = Queued()
Do m = 1 To numqueued
   Parse Pull word_out_line.m
End
word_out_line.0 = numqueued
Return
