home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD1.iso / Editor / FREDV19A.LHA / FrexxEd / fpl / wordpro.FPL < prev    next >
Encoding:
Text File  |  1995-07-16  |  14.4 KB  |  473 lines

  1. /*
  2.  * WHAT IS THIS?
  3.  *
  4.  * WordPro.FPL is perhaps the most advanced FPL program written for FrexxEd
  5.  * at this time. It brings interactive word-processor-style word wrap
  6.  * functionality to the editor.
  7.  *
  8.  * "word-processor-style" means that
  9.  * A. All word wrapping is "paragraph" oriented. All lines within the same
  10.  *    paragraph are separated with 'soft' newlines (that is a "\x01\n" in my
  11.  *    program!),
  12.  * B. If a line is longer than the right margin is set to, the words that are
  13.  *    "off the edge" are moved down to the line below and a 'soft' newline is
  14.  *    added to the end of the line. If the line below gets too long by the
  15.  *    operation, it performs the same with that line...
  16.  * C. If the first word of the line below would fit at the end of the current,
  17.  *    it is moved up. (And then the same check is done on the line below.)
  18.  */
  19.  
  20. /*
  21.  * Current restrictions:
  22.  *  o Pretty slow on large paragraphs, perhaps I'll make a limit in amount
  23.  *    of lines that can get 'fixed' on each invoke.
  24.  *  o If the first word of a line fits on the line above is only checked for
  25.  *    if the current line is out of right margin ( and '_fitprev' is on ).
  26.  *  o If the first word of the line below fits on the current line is only
  27.  *    checked for when deleting.
  28.  *  o There is no kind of left margin indentation support
  29.  */
  30.  
  31. /*
  32.  * WordProWrap()
  33.  *
  34.  * Checks the current line to see if it is longer than the margin allows.
  35.  * If it is, it performs actions to word wrap it properly
  36.  */
  37. export int WordProWrap(void)
  38. {
  39.   string word;
  40.   int sbyte = ReadInfo("byte_position");
  41.   int line = ReadInfo("line");
  42.   int sline=line;
  43.   int cursorline = line;
  44.   int jumpback;
  45.   int wrapped;
  46.   int len = ReadInfo("line_length");
  47.   int visible = Visible(0);
  48.   const int wall = ReadInfo("wall_right");
  49.   if(wall >= len)
  50.     return 1;
  51.   SetInfo(-1, "_wordpro", ReadInfo("_wordpro")+1);
  52.   do {
  53.     int steps;
  54.     int backsteps;
  55.     len = ReadInfo("line_length");
  56.     if(IsLineWordWrapped(line)) {
  57.       wrapped=1; /* it is wrapped! */
  58.       len--; /* don't count the cookie! */
  59.     }
  60.     else
  61.       wrapped=0;
  62.  
  63.     if(wall >= len)
  64.       break;
  65.  
  66.     // Request(sprintf("line %d is %d bytes long", line, len));
  67.     jumpback=1;
  68.     if(line == cursorline) {
  69.       /* the cursor-line */
  70.       if(ReadInfo("column") + (len-sbyte) >= wall) {
  71.         /* we reached the edge when appending text to the left side
  72.            of text that is about to get wrapped! */
  73.         backsteps= len-sbyte;  /* this number of steps from the current
  74.                         right edge */
  75.         jumpback=0;
  76.       }
  77.  
  78.       if(ReadInfo("WordPro_fitprev")) {
  79.         /*
  80.          * This checks if the first word on the line fits on the uppper line
  81.          */
  82.         while (IsLineWordWrapped(line-1)) {
  83.           int uplen;
  84.           GotoLine(line-1);
  85.           uplen = ReadInfo("line_length");
  86.           word = GetWord(line, 0);
  87.           if(sbyte > strlen(word) &&
  88.              uplen + strlen(word)+2 < wall) {
  89.             GotoLine(--line, len);
  90.             Backspace();
  91.             Delete();
  92.             Output(" ");
  93.             sbyte += uplen;
  94.             sline--;
  95.             //Request("We merged the line with the upper one!");
  96.           }
  97.           else {
  98.             GotoLine(line);
  99.             break;
  100.           }
  101.         }
  102.       }
  103.       /* ----- */
  104.       cursorline=-1; /* never ever do this again */
  105.       
  106.     }
  107.  
  108.     GotoLine(line, ReadInfo("line_length")); /* jump to end of line! */
  109.     do {
  110.       steps+=CursorLeftWord();
  111.     } while (line==ReadInfo("line") &&
  112.              ReadInfo("column")>1 &&
  113.              wall<ReadInfo("column"));
  114.  
  115.     if(!jumpback && (steps < backsteps)) {
  116.       /* then this is a false backstepper! */
  117.       jumpback=1;
  118.     }
  119.  
  120.     if (line==ReadInfo("line") && ReadInfo("column")>1) {
  121.       int byte = ReadInfo("byte_position");
  122.       while(GetChar(--byte) != ' ') {
  123.          steps++;
  124.          CursorLeft();
  125.          if(!byte) {
  126.             GotoLine(line,wall);
  127.             Output("\x01\n");
  128.             break 2;
  129.          }
  130.       }
  131.       byte++;
  132.       while(GetChar(--byte) == ' ')
  133.         Backspace();
  134.       Output("\x01\n");
  135.     }
  136.     /*
  137.     if(wall <= ReadInfo("column")) {
  138.       Output("\x01\n");
  139.     }
  140.     */
  141.     line++; /* we've come down one line by now! */
  142.     if(!jumpback) {
  143.       jumpback=1;
  144.       sbyte = steps-backsteps;
  145.       sline = line;
  146.     }
  147.     if(wrapped) {
  148.       //Request("This is a wrapped line, check if next word fits here!");
  149.       len = ReadInfo("line_length");
  150.       word = GetWord(line+1, 0); /* get first word on next line */
  151.       if(strlen(word)+len < wall) {
  152.         /* we think next word is gonna fit on our line! */
  153.         GotoLine(line, len); /* jump to end of line! */
  154.         Backspace(); /* get rid of our 0x01 code! */
  155.         Delete(); /* Merge next line to our! */
  156.         if(GetChar()!=' ')
  157.           Output(" "); /* make us a space! */
  158.       }
  159.       else {
  160.         //Request("Nope! It doesn't...");
  161.         if(len < wall)
  162.           wrapped=0;
  163.       }
  164.     }
  165.   } while(wrapped); /* continue until done! */
  166.   if(jumpback)
  167.     GotoLine(sline, sbyte); /* jump to start-pos! */
  168.   SetInfo(-1, "_wordpro", ReadInfo("_wordpro")-1);
  169.   Visible(visible);
  170. }
  171.  
  172. /*
  173.  * WordProDelete0x01()
  174.  *
  175.  * Called before each invoke of Delete() to make a deletion of the 'soft'
  176.  * newline character (ASCII 0x01) make a deletion of the following
  177.  * newline too, and a decent word wrap if the line gets too long!
  178.  */
  179. int newlinedelete;
  180. export int WordProDelete0x01(int number)
  181. {
  182.   if(1 == GetChar()) { /* are we standing on a 0x01 character? */
  183.     SetInfo(-1, "_wordpro", ReadInfo("_wordpro")+1);
  184.     if(number>1) /* specified number? */
  185.       number--;
  186.     Delete(number+2); /* delete the 0x01 and newline too then! */
  187.     WordProWrap(); /* wrap this long line! */
  188.     SetInfo(-1, "_wordpro", ReadInfo("_wordpro")-1);
  189.     return 1; /* quit the actual Delete() */
  190.   }
  191. }
  192.  
  193. /*
  194.  * WordProDelete0x01()
  195.  *
  196.  * Called after each invoke of Delete() to make a decent word wrap if the
  197.  * line gets short enough to fit the first word on the line below!
  198.  */
  199. export int WordProDelete(void)
  200. {
  201.   int line=ReadInfo("line");
  202.   if(IsLineWordWrapped(line)) {
  203.     int len;
  204.     int sline=line;
  205.     int sbyte=ReadInfo("byte_position");
  206.     int visible=Visible(0);
  207.     string word;
  208.     SetInfo(-1, "_wordpro", ReadInfo("_wordpro")+1);
  209.     while(line <= ReadInfo("lines")) {
  210.       word = GetWord(line+1, 0); /* get first word on next line */
  211.       len = ReadInfo("line_length") + strlen(word)+1; /* a space too! */
  212.       if(ReadInfo("wall_right") >= len) {
  213.         GotoLine(line++, len);
  214.         Backspace(); /* remove magic cookie! */
  215.         Delete(); /* remove newline */
  216.         Output(" ");
  217.         WordProWrap(); /* do the dance! */
  218.       }
  219.       else
  220.         break;
  221.     }
  222.     GotoLine(sline, sbyte); /* jump to start-pos! */      
  223.     SetInfo(-1, "_wordpro", ReadInfo("_wordpro")-1);
  224.     Visible(visible);
  225.   }  
  226. }
  227.  
  228. /*
  229.  * WordProSave()
  230.  *
  231.  * Called before the actual save is done. If the user confirms the question,
  232.  * it replaces all soft newlines to spaces and then saves it like that.
  233.  */
  234. int oursavehook;
  235. export int WordProSave(string file, string pack)
  236. {
  237.   int new;
  238.   int savemode = ReadInfo("wordpro_save");
  239.   if(3 == savemode) {
  240.     savemode = Request("How do you want it saved?", "Save option",
  241.                        "Raw|Softs too|Only hards|Cancel");
  242.     if(!savemode--) {
  243.       return 1;
  244.     }
  245.   }
  246.   if(!oursavehook && savemode) {
  247.     int us = GetEntryID();
  248.     new = New();
  249.     oursavehook=1; /* prevent us from getting recursive! */
  250.     if(new) {
  251.       string filename;
  252.       string replacedsoft;
  253.       CurrentBuffer(new); /* jump to the new one */
  254.       BlockPaste(us); /* paste the original buffer in the new */
  255.       GotoLine(1); /* go to the top! */
  256.  
  257.       if(savemode==2) {
  258.         /* this is "only hard" newlines should be left, replace all softies
  259.            with a single space! */
  260.         replacedsoft = " ";
  261.       }
  262.       else {
  263.         /* Keep the soft newlines as newlines in the output! */
  264.         replacedsoft = "\n";
  265.       }
  266.       Replace(1, "\x01\n", replacedsoft, "f+"); /* replace all soft newlines */
  267.       
  268.       filename = ReadInfo("full_file_name", us); /* get file name */
  269.       if(strlen(file))
  270.         /* done like this to still support Save() with a given name */
  271.         filename=file;
  272.       Save(filename, pack); /* save the new buffer to the original file */
  273.       CurrentBuffer(us); /* jump back to the orignal buffer */
  274.  
  275.       /*
  276.        * Now, write the date and time of our "faked" save into the
  277.        * info variable for our good old buffer to maintain the proper
  278.        * data! (and most of all, to avoid that nasty 'FileChanged'
  279.        * exception when trying to save a file that is older than the file
  280.        * actually is on disk!)
  281.        */
  282.       SetInfo(us, "ds_Days", ReadInfo("ds_Days", new));
  283.       SetInfo(us, "ds_Minute", ReadInfo("ds_Minute", new));
  284.       SetInfo(us, "ds_Tick", ReadInfo("ds_Tick", new));
  285.  
  286.       SetInfo(us, "changes", 0); /* clear the changes flag! */
  287.       Kill(new); /* kill our temporary buffer */
  288.     }
  289.     oursavehook=0; /* allow us to get started once again! */
  290.   }
  291.   return new; /* if non-zero, the "real" save is stopped */
  292. }
  293.  
  294. /*
  295.  * WordProOpenAndWrap()
  296.  *
  297.  * This function takes the specified file, or if none is specified, prompts
  298.  * for one, loads it into a new buffer and word wraps it according to
  299.  * its knowledge.
  300.  */
  301. int export WordProOpenAndWrap(string file)
  302. {
  303.   int new;
  304.   if(!strlen(file)) {
  305.     file=PromptFile();
  306.     if(!strlen(file))
  307.       /* cancel or error occured! */
  308.       return 1;
  309.   }
  310.   new = New();
  311.   if(new) {
  312.     SetInfo(-1, "_wordpro", ReadInfo("_wordpro")+1); /* prevent recurse */
  313.     CurrentBuffer(new); /* jump to new buffer */
  314.     Load(file); /* load the specified file */
  315.     WordProWrapLines(1, ReadInfo("lines")); /* do the entire buffer! */
  316.     SetInfo(-1, "_wordpro", ReadInfo("_wordpro")-1); /* allow recurse */
  317.     SetInfo(-1, "wordpro", 1); /* 'wordpro' is enabled for this buffer! */
  318.   }
  319.   else
  320.     return 1;
  321. }
  322.  
  323. int export WordProWrapBuffer()
  324. {
  325.   SetInfo(-1, "_wordpro", ReadInfo("_wordpro")+1); /* prevent recurse */
  326.   WordProWrapLines(1, ReadInfo("lines")); /* do the entire buffer! */
  327.   SetInfo(-1, "_wordpro", ReadInfo("_wordpro")-1); /* allow recurse */
  328. }
  329.  
  330. int export WordProWrapBlock()
  331. {
  332.   if(ReadInfo("block_exist")) {
  333.     BlockMark(0);
  334.     WordProWrapLines(ReadInfo("block_begin_y"), ReadInfo("block_end_y"));
  335.   }
  336.   else
  337.     ReturnStatus("No block marked!");
  338. }
  339.  
  340. int export WordProWrapLines(int firstline, int lastline)
  341. {
  342.   int line;
  343.   int numlines;
  344.   int len;
  345.   int count;
  346.  
  347.   SetInfo(-1, "wordpro", 1); /* we wanna run wordpro dammit! ;) */
  348.  
  349.   /* Do the tango!
  350.    *
  351.    * Combine all 'paragraphs' with soft newlines!
  352.    */
  353.   numlines = ReadInfo("lines"); /* read number of lines */
  354.   for(line= firstline; line < lastline; line++) { /* the last line can't be soft! */
  355.     len = GetByte(999999, line); /* get byte position */
  356.     if(len > ReadInfo("wall_right")/2 &&
  357.        !IsLineWordWrapped(line)) {
  358.       /* the text of this line reaches longer than half the width */
  359.       /* and it isn't previously wrapped (like if the file was saved 'raw'
  360.          in a previous WordPro editing session)! */
  361.       GotoLine(line, len); /* goto end of line */
  362.  
  363.       /* The expression just above does not fully function in FrexxEd 1.7
  364.          and earlier if the length of the line is longer than the width
  365.          of the screen/window... */
  366.       
  367.       if(!Isspace(GetChar(0, line+1))) {
  368.         /* The paragraph seems to continue on the following line,
  369.            since the first column of that line isn't white space! */
  370.         Output("\x01");
  371.       }
  372.     }
  373.     /* next one please! */
  374.   }
  375.   /*
  376.    * Now, let's scan all lines and wrap them to a decent level!
  377.    */
  378.   for(line= firstline; line <= lastline;) {
  379.     GotoLine(line); /* jump to the line in question! */
  380.     WordProWrap(); /* do the secret wrap trick! */
  381.     count = ReadInfo("lines")-numlines; /* this amount of new lines! */
  382.     numlines += count; /* we're at this amount now! */
  383.     lastline += count; /* add to this one too! */
  384.     if(count)
  385.       line += count; /* skip those new ones since they're already wrapped! */
  386.     else
  387.       line++;
  388.   }
  389.   SetInfo(-1, "_wordpro", ReadInfo("_wordpro")-1); /* allow yet again! */
  390. }
  391.  
  392. export void WordProPrefs()
  393. {
  394.   PromptInfo(-1, "WordPro Preferences", -1, -1,
  395.              "wordpro", "wall_right", "wordpro_save", "wordpro_fitprev",
  396.              "wordpro_open");
  397. }
  398.  
  399. int IsLineWordWrapped(int line)
  400. {
  401.   if(line>0) {
  402.     int len= GetByte(999999, line);
  403.     if(len>1 && (1 == GetChar(len-1, line))) {
  404.       return 1;
  405.     }
  406.   }
  407.   return 0;
  408. }
  409.  
  410. ReadInfo("_wordpro");
  411. if(GetErrNo()) { /* just a way to make the menu only once, even if this file
  412.                     is executed repeatedly! */
  413.   /*
  414.    * Create our menu setup:
  415.    */
  416.   MenuAdd("t", "WordPro");
  417.     MenuAdd("i", "Open...", "WordProOpenAndWrap(\"\");", "control w o");
  418.     MenuAdd("i", "Wrap Block", "WordProWrapBlock();", "control w b");
  419.     MenuAdd("i", "Save...", "Save();", "control w s");
  420.     MenuAdd("i", "Prefs", "WordProPrefs();");
  421.   
  422.   MenuBuild();
  423. }
  424. /*
  425.  * This little beast is here only to prevent recursion where we don't want
  426.  * it...
  427.  */
  428. ConstructInfo("_wordpro", "", "", "ILH", "", 0, 999, 0);
  429.  
  430. /*
  431.  * This is the general right-edge setting.
  432.  */
  433. ConstructInfo("wall_right", "", "", "WIL(display)", "", 0, 999, 79);
  434.  
  435. /*
  436.  * Toggle this mode on/off with this!
  437.  */
  438. ConstructInfo("wordpro", "", "", "WBL(system)", "", 0, 0);
  439.  
  440. /*
  441.  * Control how the saving is performed with this.
  442.  */
  443. ConstructInfo("wordpro_save", "", "", "WCG(system)", "Raw|Softs too|Only Hards|Query", 0, 0, 2);
  444.  
  445. /*
  446.  * Make all the regular loads word wrap the file!
  447.  */
  448. ConstructInfo("wordpro_open", "", "", "WBG(system)", "", 0, 0, 0);
  449.  
  450. /*
  451.  * This variable enables the wordpro script to check if the first word of
  452.  * the line fits on the line above.
  453.  */
  454. ConstructInfo("wordpro_fitprev", "", "", "WBG(system)", "", 0, 0, 1);
  455.  
  456. FACT(0x01, 'S', "^", ' '); /* non-visible character! */
  457.  
  458. AddMode(0,"wordpro", "","");                // Add as minor mode!
  459.  
  460. /*
  461.  * All this can only be accomplished by some pretty extensive hooking...
  462.  */
  463.  
  464. HookPast("Output", "WordProWrap();", "wordpro&!_wordpro");
  465. HookPast("BlockPaste", "WordProWrap();", "wordpro&!_wordpro");
  466. HookPast("Delete", "WordProDelete();", "wordpro&!_wordpro");
  467. HookPast("Backspace", "WordProDelete();", "wordpro&!_wordpro");
  468. HookPast("DeleteWord", "WordProDelete();", "wordpro&!_wordpro");
  469. HookPast("BackspaceWord", "WordProDelete();", "wordpro&!_wordpro");
  470. Hook("Save", "WordProSave", "wordpro");
  471. Hook("Delete", "WordProDelete0x01", "wordpro&!_wordpro");
  472. Hook("GotFile", "WordProWrapBuffer();", "wordpro_open&!_wordpro");
  473.