home *** CD-ROM | disk | FTP | other *** search
- /*
- * WHAT IS THIS?
- *
- * WordPro.FPL is perhaps the most advanced FPL program written for FrexxEd
- * at this time. It brings interactive word-processor-style word wrap
- * functionality to the editor.
- *
- * "word-processor-style" means that
- * A. All word wrapping is "paragraph" oriented. All lines within the same
- * paragraph are separated with 'soft' newlines (that is a "\x01\n" in my
- * program!),
- * B. If a line is longer than the right margin is set to, the words that are
- * "off the edge" are moved down to the line below and a 'soft' newline is
- * added to the end of the line. If the line below gets too long by the
- * operation, it performs the same with that line...
- * C. If the first word of the line below would fit at the end of the current,
- * it is moved up. (And then the same check is done on the line below.)
- */
-
- /*
- * Current restrictions:
- * o Pretty slow on large paragraphs, perhaps I'll make a limit in amount
- * of lines that can get 'fixed' on each invoke.
- * o If the first word of a line fits on the line above is only checked for
- * if the current line is out of right margin ( and '_fitprev' is on ).
- * o If the first word of the line below fits on the current line is only
- * checked for when deleting.
- * o There is no kind of left margin indentation support
- */
-
- /*
- * WordProWrap()
- *
- * Checks the current line to see if it is longer than the margin allows.
- * If it is, it performs actions to word wrap it properly
- */
- export int WordProWrap(void)
- {
- string word;
- int sbyte = ReadInfo("byte_position");
- int line = ReadInfo("line");
- int sline=line;
- int cursorline = line;
- int jumpback;
- int wrapped;
- int len = ReadInfo("line_length");
- int visible = Visible(0);
- const int wall = ReadInfo("wall_right");
- if(wall >= len)
- return 1;
- SetInfo(-1, "_wordpro", ReadInfo("_wordpro")+1);
- do {
- int steps;
- int backsteps;
- len = ReadInfo("line_length");
- if(IsLineWordWrapped(line)) {
- wrapped=1; /* it is wrapped! */
- len--; /* don't count the cookie! */
- }
- else
- wrapped=0;
-
- if(wall >= len)
- break;
-
- // Request(sprintf("line %d is %d bytes long", line, len));
- jumpback=1;
- if(line == cursorline) {
- /* the cursor-line */
- if(ReadInfo("column") + (len-sbyte) >= wall) {
- /* we reached the edge when appending text to the left side
- of text that is about to get wrapped! */
- backsteps= len-sbyte; /* this number of steps from the current
- right edge */
- jumpback=0;
- }
-
- if(ReadInfo("WordPro_fitprev")) {
- /*
- * This checks if the first word on the line fits on the uppper line
- */
- while (IsLineWordWrapped(line-1)) {
- int uplen;
- GotoLine(line-1);
- uplen = ReadInfo("line_length");
- word = GetWord(line, 0);
- if(sbyte > strlen(word) &&
- uplen + strlen(word)+2 < wall) {
- GotoLine(--line, len);
- Backspace();
- Delete();
- Output(" ");
- sbyte += uplen;
- sline--;
- //Request("We merged the line with the upper one!");
- }
- else {
- GotoLine(line);
- break;
- }
- }
- }
- /* ----- */
- cursorline=-1; /* never ever do this again */
-
- }
-
- GotoLine(line, ReadInfo("line_length")); /* jump to end of line! */
- do {
- steps+=CursorLeftWord();
- } while (line==ReadInfo("line") &&
- ReadInfo("column")>1 &&
- wall<ReadInfo("column"));
-
- if(!jumpback && (steps < backsteps)) {
- /* then this is a false backstepper! */
- jumpback=1;
- }
-
- if (line==ReadInfo("line") && ReadInfo("column")>1) {
- int byte = ReadInfo("byte_position");
- while(GetChar(--byte) != ' ') {
- steps++;
- CursorLeft();
- if(!byte) {
- GotoLine(line,wall);
- Output("\x01\n");
- break 2;
- }
- }
- byte++;
- while(GetChar(--byte) == ' ')
- Backspace();
- Output("\x01\n");
- }
- /*
- if(wall <= ReadInfo("column")) {
- Output("\x01\n");
- }
- */
- line++; /* we've come down one line by now! */
- if(!jumpback) {
- jumpback=1;
- sbyte = steps-backsteps;
- sline = line;
- }
- if(wrapped) {
- //Request("This is a wrapped line, check if next word fits here!");
- len = ReadInfo("line_length");
- word = GetWord(line+1, 0); /* get first word on next line */
- if(strlen(word)+len < wall) {
- /* we think next word is gonna fit on our line! */
- GotoLine(line, len); /* jump to end of line! */
- Backspace(); /* get rid of our 0x01 code! */
- Delete(); /* Merge next line to our! */
- if(GetChar()!=' ')
- Output(" "); /* make us a space! */
- }
- else {
- //Request("Nope! It doesn't...");
- if(len < wall)
- wrapped=0;
- }
- }
- } while(wrapped); /* continue until done! */
- if(jumpback)
- GotoLine(sline, sbyte); /* jump to start-pos! */
- SetInfo(-1, "_wordpro", ReadInfo("_wordpro")-1);
- Visible(visible);
- }
-
- /*
- * WordProDelete0x01()
- *
- * Called before each invoke of Delete() to make a deletion of the 'soft'
- * newline character (ASCII 0x01) make a deletion of the following
- * newline too, and a decent word wrap if the line gets too long!
- */
- int newlinedelete;
- export int WordProDelete0x01(int number)
- {
- if(1 == GetChar()) { /* are we standing on a 0x01 character? */
- SetInfo(-1, "_wordpro", ReadInfo("_wordpro")+1);
- if(number>1) /* specified number? */
- number--;
- Delete(number+2); /* delete the 0x01 and newline too then! */
- WordProWrap(); /* wrap this long line! */
- SetInfo(-1, "_wordpro", ReadInfo("_wordpro")-1);
- return 1; /* quit the actual Delete() */
- }
- }
-
- /*
- * WordProDelete0x01()
- *
- * Called after each invoke of Delete() to make a decent word wrap if the
- * line gets short enough to fit the first word on the line below!
- */
- export int WordProDelete(void)
- {
- int line=ReadInfo("line");
- if(IsLineWordWrapped(line)) {
- int len;
- int sline=line;
- int sbyte=ReadInfo("byte_position");
- int visible=Visible(0);
- string word;
- SetInfo(-1, "_wordpro", ReadInfo("_wordpro")+1);
- while(line <= ReadInfo("lines")) {
- word = GetWord(line+1, 0); /* get first word on next line */
- len = ReadInfo("line_length") + strlen(word)+1; /* a space too! */
- if(ReadInfo("wall_right") >= len) {
- GotoLine(line++, len);
- Backspace(); /* remove magic cookie! */
- Delete(); /* remove newline */
- Output(" ");
- WordProWrap(); /* do the dance! */
- }
- else
- break;
- }
- GotoLine(sline, sbyte); /* jump to start-pos! */
- SetInfo(-1, "_wordpro", ReadInfo("_wordpro")-1);
- Visible(visible);
- }
- }
-
- /*
- * WordProSave()
- *
- * Called before the actual save is done. If the user confirms the question,
- * it replaces all soft newlines to spaces and then saves it like that.
- */
- int oursavehook;
- export int WordProSave(string file, string pack)
- {
- int new;
- int savemode = ReadInfo("wordpro_save");
- if(3 == savemode) {
- savemode = Request("How do you want it saved?", "Save option",
- "Raw|Softs too|Only hards|Cancel");
- if(!savemode--) {
- return 1;
- }
- }
- if(!oursavehook && savemode) {
- int us = GetEntryID();
- new = New();
- oursavehook=1; /* prevent us from getting recursive! */
- if(new) {
- string filename;
- string replacedsoft;
- CurrentBuffer(new); /* jump to the new one */
- BlockPaste(us); /* paste the original buffer in the new */
- GotoLine(1); /* go to the top! */
-
- if(savemode==2) {
- /* this is "only hard" newlines should be left, replace all softies
- with a single space! */
- replacedsoft = " ";
- }
- else {
- /* Keep the soft newlines as newlines in the output! */
- replacedsoft = "\n";
- }
- Replace(1, "\x01\n", replacedsoft, "f+"); /* replace all soft newlines */
-
- filename = ReadInfo("full_file_name", us); /* get file name */
- if(strlen(file))
- /* done like this to still support Save() with a given name */
- filename=file;
- Save(filename, pack); /* save the new buffer to the original file */
- CurrentBuffer(us); /* jump back to the orignal buffer */
-
- /*
- * Now, write the date and time of our "faked" save into the
- * info variable for our good old buffer to maintain the proper
- * data! (and most of all, to avoid that nasty 'FileChanged'
- * exception when trying to save a file that is older than the file
- * actually is on disk!)
- */
- SetInfo(us, "ds_Days", ReadInfo("ds_Days", new));
- SetInfo(us, "ds_Minute", ReadInfo("ds_Minute", new));
- SetInfo(us, "ds_Tick", ReadInfo("ds_Tick", new));
-
- SetInfo(us, "changes", 0); /* clear the changes flag! */
- Kill(new); /* kill our temporary buffer */
- }
- oursavehook=0; /* allow us to get started once again! */
- }
- return new; /* if non-zero, the "real" save is stopped */
- }
-
- /*
- * WordProOpenAndWrap()
- *
- * This function takes the specified file, or if none is specified, prompts
- * for one, loads it into a new buffer and word wraps it according to
- * its knowledge.
- */
- int export WordProOpenAndWrap(string file)
- {
- int new;
- if(!strlen(file)) {
- file=PromptFile();
- if(!strlen(file))
- /* cancel or error occured! */
- return 1;
- }
- new = New();
- if(new) {
- SetInfo(-1, "_wordpro", ReadInfo("_wordpro")+1); /* prevent recurse */
- CurrentBuffer(new); /* jump to new buffer */
- Load(file); /* load the specified file */
- WordProWrapLines(1, ReadInfo("lines")); /* do the entire buffer! */
- SetInfo(-1, "_wordpro", ReadInfo("_wordpro")-1); /* allow recurse */
- SetInfo(-1, "wordpro", 1); /* 'wordpro' is enabled for this buffer! */
- }
- else
- return 1;
- }
-
- int export WordProWrapBuffer()
- {
- SetInfo(-1, "_wordpro", ReadInfo("_wordpro")+1); /* prevent recurse */
- WordProWrapLines(1, ReadInfo("lines")); /* do the entire buffer! */
- SetInfo(-1, "_wordpro", ReadInfo("_wordpro")-1); /* allow recurse */
- }
-
- int export WordProWrapBlock()
- {
- if(ReadInfo("block_exist")) {
- BlockMark(0);
- WordProWrapLines(ReadInfo("block_begin_y"), ReadInfo("block_end_y"));
- }
- else
- ReturnStatus("No block marked!");
- }
-
- int export WordProWrapLines(int firstline, int lastline)
- {
- int line;
- int numlines;
- int len;
- int count;
-
- SetInfo(-1, "wordpro", 1); /* we wanna run wordpro dammit! ;) */
-
- /* Do the tango!
- *
- * Combine all 'paragraphs' with soft newlines!
- */
- numlines = ReadInfo("lines"); /* read number of lines */
- for(line= firstline; line < lastline; line++) { /* the last line can't be soft! */
- len = GetByte(999999, line); /* get byte position */
- if(len > ReadInfo("wall_right")/2 &&
- !IsLineWordWrapped(line)) {
- /* the text of this line reaches longer than half the width */
- /* and it isn't previously wrapped (like if the file was saved 'raw'
- in a previous WordPro editing session)! */
- GotoLine(line, len); /* goto end of line */
-
- /* The expression just above does not fully function in FrexxEd 1.7
- and earlier if the length of the line is longer than the width
- of the screen/window... */
-
- if(!Isspace(GetChar(0, line+1))) {
- /* The paragraph seems to continue on the following line,
- since the first column of that line isn't white space! */
- Output("\x01");
- }
- }
- /* next one please! */
- }
- /*
- * Now, let's scan all lines and wrap them to a decent level!
- */
- for(line= firstline; line <= lastline;) {
- GotoLine(line); /* jump to the line in question! */
- WordProWrap(); /* do the secret wrap trick! */
- count = ReadInfo("lines")-numlines; /* this amount of new lines! */
- numlines += count; /* we're at this amount now! */
- lastline += count; /* add to this one too! */
- if(count)
- line += count; /* skip those new ones since they're already wrapped! */
- else
- line++;
- }
- SetInfo(-1, "_wordpro", ReadInfo("_wordpro")-1); /* allow yet again! */
- }
-
- export void WordProPrefs()
- {
- PromptInfo(-1, "WordPro Preferences", -1, -1,
- "wordpro", "wall_right", "wordpro_save", "wordpro_fitprev",
- "wordpro_open");
- }
-
- int IsLineWordWrapped(int line)
- {
- if(line>0) {
- int len= GetByte(999999, line);
- if(len>1 && (1 == GetChar(len-1, line))) {
- return 1;
- }
- }
- return 0;
- }
-
- ReadInfo("_wordpro");
- if(GetErrNo()) { /* just a way to make the menu only once, even if this file
- is executed repeatedly! */
- /*
- * Create our menu setup:
- */
- MenuAdd("t", "WordPro");
- MenuAdd("i", "Open...", "WordProOpenAndWrap(\"\");", "control w o");
- MenuAdd("i", "Wrap Block", "WordProWrapBlock();", "control w b");
- MenuAdd("i", "Save...", "Save();", "control w s");
- MenuAdd("i", "Prefs", "WordProPrefs();");
-
- MenuBuild();
- }
- /*
- * This little beast is here only to prevent recursion where we don't want
- * it...
- */
- ConstructInfo("_wordpro", "", "", "ILH", "", 0, 999, 0);
-
- /*
- * This is the general right-edge setting.
- */
- ConstructInfo("wall_right", "", "", "WIL(display)", "", 0, 999, 79);
-
- /*
- * Toggle this mode on/off with this!
- */
- ConstructInfo("wordpro", "", "", "WBL(system)", "", 0, 0);
-
- /*
- * Control how the saving is performed with this.
- */
- ConstructInfo("wordpro_save", "", "", "WCG(system)", "Raw|Softs too|Only Hards|Query", 0, 0, 2);
-
- /*
- * Make all the regular loads word wrap the file!
- */
- ConstructInfo("wordpro_open", "", "", "WBG(system)", "", 0, 0, 0);
-
- /*
- * This variable enables the wordpro script to check if the first word of
- * the line fits on the line above.
- */
- ConstructInfo("wordpro_fitprev", "", "", "WBG(system)", "", 0, 0, 1);
-
- FACT(0x01, 'S', "^", ' '); /* non-visible character! */
-
- AddMode(0,"wordpro", "",""); // Add as minor mode!
-
- /*
- * All this can only be accomplished by some pretty extensive hooking...
- */
-
- HookPast("Output", "WordProWrap();", "wordpro&!_wordpro");
- HookPast("BlockPaste", "WordProWrap();", "wordpro&!_wordpro");
- HookPast("Delete", "WordProDelete();", "wordpro&!_wordpro");
- HookPast("Backspace", "WordProDelete();", "wordpro&!_wordpro");
- HookPast("DeleteWord", "WordProDelete();", "wordpro&!_wordpro");
- HookPast("BackspaceWord", "WordProDelete();", "wordpro&!_wordpro");
- Hook("Save", "WordProSave", "wordpro");
- Hook("Delete", "WordProDelete0x01", "wordpro&!_wordpro");
- Hook("GotFile", "WordProWrapBuffer();", "wordpro_open&!_wordpro");
-