SpellingToolServicesImpl.mesa
Copyright Ó 1985, 1987, 1989, 1992 by Xerox Corporation. All rights reserved.
Jack Kent August 18, 1987 2:19:05 pm PDT
Tim Diebert: August 18, 1989 12:36:08 pm PDT
Willie-s, June 1, 1992 10:11 pm PDT
DIRECTORY
Dictionary,
Atom,
BasicTime,
Convert,
IO,
IOTioga,
Menus USING [MenuProc],
RefTab USING [Create, Erase, Fetch, Ref, Store],
Rope,
Rosary,
SpellingToolServices,
SpellingToolShared USING [Selection, ProcessSelection, ToRope],
TextEdit,
TextLooks,
Tioga,
TiogaOps USING [CallWithLocks, NoSelection],
TiogaOpsDefs USING [Ref];
SpellingToolServicesImpl: CEDAR MONITOR
IMPORTS Dictionary, Atom, BasicTime, Convert, IO, IOTioga, RefTab, Rope, Rosary, SpellingToolShared, TextEdit, TextLooks, TiogaOps
EXPORTS SpellingToolServices = {
STREAM: TYPE = IO.STREAM;
ROPE: TYPE = Rope.ROPE;
AtomList: TYPE = LIST OF ATOM;
AtomListList: TYPE = LIST OF AtomList;
definitionCaveat: BOOL ¬ FALSE;
totalDefinitionsCnt, totalDefinitionsWorkedCount: INT ¬ 0;
permMessage: STREAM ¬ NIL;
dictionary: ATOM = $AmericanHeritage;
checker: ATOM = $Proofreader;
morph: ATOM = $EnglishMorph;
conjug: ATOM = NIL;
looksTranslator: RefTab.Ref = RefTab.Create[];
InitializeDictionaryServer: PUBLIC PROC [outputStream: STREAM] = {
ENABLE {
UNWIND => {};
Dictionary.Error => {
SELECT problem FROM
courier => PutCourierError[permMessage, explanation];
service => PutServiceError[permMessage, explanation];
ENDCASE => ERROR;
CONTINUE; -- was missing so error was not really being caught
};
};
permMessage ¬ outputStream;
SetupLooksTranslator[];
};
DefinitionButton: PUBLIC Menus.MenuProc = TRUSTED {
theWord, wordNoBlank: ROPE;
DictionaryCommand: PRIVATE PROC [theWord: ROPE] = TRUSTED {
entryHandle, item: ROPE ¬ NIL;
definition: Dictionary.Definition;
IF theWord.Length[] # 0 THEN definition ¬ Dictionary.GetDefinition[theWord, dictionary ! Dictionary.Error => {definition.definition ¬ NIL; CONTINUE}];
IF definition.definition.Length[] # 0 THEN {
PutWithRuns[permMessage, definition.definition, definition.looks];
IO.PutRope[permMessage, "\n"];
totalDefinitionsWorkedCount ¬ totalDefinitionsWorkedCount + 1}
ELSE IO.PutRope[permMessage, "not found\n"];
};
{
Locker: PRIVATE PROC [root: TiogaOpsDefs.Ref] = TRUSTED {
ExtractOneWord: PRIVATE PROC [word: REF TEXT] RETURNS [stop: BOOLEAN ← TRUE] = TRUSTED {wordNoBlank ← Rope.FromRefText[word]};
now: BasicTime.Unpacked ~ BasicTime.Unpack[BasicTime.Now[]];
s: SpellingToolShared.Selection ¬ SpellingToolShared.ProcessSelection[FALSE,TRUE, TRUE].s;
[] ← SpellingToolShared.MapWordsInSelection[s.start, s.end, ExtractOneWord, TRUE, TRUE, TRUE];
wordNoBlank ¬ SpellingToolShared.ToRope[s];
IF Rope.Length[wordNoBlank]=0 THEN
IO.PutRope[permMessage, "No word has been selected.\n"]
ELSE {
IF now.month=April AND now.day=1 AND now.second<30 THEN wordNoBlank ¬ "Fool";
IO.PutF1[permMessage, "Looking up the definition of \"%g\"...\n", IO.rope[wordNoBlank]];
theWord ¬ wordNoBlank; -- Bug in Dictionary server requires it.
};
};
IF ~definitionCaveat THEN
IO.PutRope[permMessage, "Warning: the definition facility often fails to work.\n"];
TiogaOps.CallWithLocks[Locker ! TiogaOps.NoSelection => {
GOTO dictionaryBlownAway}];
definitionCaveat ¬ TRUE;
IF theWord = NIL THEN {
RETURN;
};
totalDefinitionsCnt ¬ totalDefinitionsCnt + 1;
DictionaryCommand[theWord];
EXITS dictionaryBlownAway => NULL;
};
};
FinalizeDictionaryServer: PUBLIC PROC [] = {
permMessage ¬ NIL;
};
DefinitionStats: PUBLIC PROC [] RETURNS [totalDefinitions, totalDefinitionsWorked: INT] = {
totalDefinitions ¬ totalDefinitionsCnt;
totalDefinitionsWorked ¬ totalDefinitionsWorkedCount;
};
BruteForceCorrection: PUBLIC PROC [word: ROPE, f: PROC [REF TEXT] RETURNS [BOOL], buffer: REF TEXT] RETURNS [corrections: LIST OF ROPE ¬ NIL, newBuffer: REF TEXT] = {
Generates all words close to "word" and returns a list of those for which f returns TRUE. The generation of close words proceeds in the usual brute-force manner: transpositions of adjacent letters in the word are considered first, then deletions of single letters, then insertions of single letters from 'a to 'z, and finally replacement of single letters by one of the other twenty five letters between 'a and 'z. The corrections proposed try to mimic the same capitalization style of the root word.
s: CARDINAL ¬ word.Size[];
potentialCorrections: LIST OF ROPE;
Test: PROC [w: REF TEXT] = INLINE {
Tests to see if a correction is in the word list and adds it to the correction list if it is.
IF f[w] THEN
corrections ¬ CONS[Rope.FromRefText[w], corrections];
};
potentialCorrections ¬ Dictionary.Corrections[word: word, language: checker];
for each word in potentialCorrections, put it in corrections if it satisfies f
FOR pc: LIST OF ROPE ¬ potentialCorrections, pc.rest UNTIL pc = NIL DO
flatten rope
refText: REF TEXT ¬ Rope.ToRefText[base: pc.first];
Test[refText];
ENDLOOP;
};
Define: PROC [word: ROPE] RETURNS [definition: Dictionary.Definition] = {
ENABLE {
UNWIND => {};
Dictionary.Error => {
SELECT problem FROM
courier => PutCourierError[permMessage, explanation];
service => PutServiceError[permMessage, explanation];
ENDCASE => ERROR;
GOTO Out;
};
};
definition ¬ Dictionary.GetDefinition[word: word, dictionary: dictionary];
EXITS Out => RETURN[NIL];
};
Conjugate: PUBLIC PROC [word: ROPE] RETURNS [conjugationsList: Dictionary.ConjugationsList] = {
conjugationsList ← Dictionary.Conjugate[word: word, form: $Single, alternates: $Mumble, language: conjug];
};
Pronunciation: PUBLIC PROC [word: ROPE] RETURNS [wordPronounced: ROPE] = {
ENABLE {
UNWIND => {};
Dictionary.Error => {
SELECT problem FROM
courier => PutCourierError[permMessage, explanation];
service => PutServiceError[permMessage, explanation];
ENDCASE => ERROR;
GOTO Out;
};
};
IF Rope.Length[wordPronounced] =0 THEN wordPronounced ¬ "\n not found ";
wordPronounced ¬ Rope.Cat[wordPronounced, "\n", Dictionary.Pronunciation[word: word, dictionary: dictionary]];
EXITS Out => RETURN[NIL];
};
Synonyms: PUBLIC PROC [word: ROPE] RETURNS [listOfSynonyms: ROPE] = {
ENABLE {
UNWIND => {};
Dictionary.Error => {
SELECT problem FROM
courier => PutCourierError[permMessage, explanation];
service => PutServiceError[permMessage, explanation];
ENDCASE => ERROR;
GOTO Out;
};
};
synonymClassesList: Dictionary.SynonymClassesList ¬ Dictionary.Synonyms[word: word, dictionary: dictionary].synonymList;
FOR classList: Dictionary.SynonymClassesList ¬ synonymClassesList, classList.rest UNTIL classList = NIL DO
FOR wordList: Dictionary.SynonymClassList ¬ classList.first, wordList.rest UNTIL wordList = NIL DO
listOfSynonyms ¬ Rope.Cat[listOfSynonyms, " ",wordList.first];
ENDLOOP;
listOfSynonyms ¬ Rope.Concat[listOfSynonyms,"\n"];
ENDLOOP;
listOfSynonyms ¬ IF Rope.Length[listOfSynonyms] =0 THEN "\n not found "
ELSE Rope.Concat["\n",listOfSynonyms];
EXITS Out => RETURN[NIL];
};
WordNerd: PUBLIC PROC [words: ROPE, minKeyWords: INT, minWords: INT, maxWords: INT, nerd: SpellingToolServices.NerdType] RETURNS [listOfNerds: ROPE] = {
ENABLE {
UNWIND => {};
Dictionary.Error => {
SELECT problem FROM
courier => PutCourierError[permMessage, explanation];
service => PutServiceError[permMessage, explanation];
ENDCASE => ERROR;
GOTO Out;
};
};
make words into list of words
nerdName: ATOM ¬ IF nerd=EtymologyNerd THEN $EtymologyNerd ELSE $WordNerd;
intersectionResultsList: Dictionary.IntersectionResultsList ¬ Dictionary.SearchForWord[unparsedClasses: words, minKeyWords: minKeyWords, minWord: minWords, maxWord: maxWords, dictionary: nerdName];
FOR nerdList: Dictionary.IntersectionResultsList ¬ intersectionResultsList, nerdList.rest UNTIL nerdList = NIL DO
FOR keyList: Dictionary.WordsList ¬ nerdList.first.keys, keyList.rest UNTIL keyList = NIL DO
listOfNerds ¬ Rope.Cat[listOfNerds, " ",keyList.first];
ENDLOOP;
listOfNerds ¬ Rope.Concat[listOfNerds,"\n"];
FOR resultList: Dictionary.WordsList ¬ nerdList.first.results, resultList.rest UNTIL resultList = NIL DO
listOfNerds ¬ Rope.Cat[listOfNerds, " ",resultList.first];
ENDLOOP;
listOfNerds ¬ Rope.Concat[listOfNerds,"\n\n"];
ENDLOOP;
listOfNerds ¬ IF Rope.Length[listOfNerds] =0 THEN "\n not found " ELSE Rope.Concat["\n",listOfNerds];
EXITS Out => RETURN[NIL];
};
SetupLooksTranslator: PRIVATE PROC [] = {
looksDefs: AtomListList = Dictionary.GetLooks[dictionary];
RefTab.Erase[looksTranslator];
FOR defs: AtomListList ¬ looksDefs, defs.rest WHILE defs # NIL DO
def: AtomList = defs.first;
dictLook: ATOM = def.first;
cedarLooks: REF TextLooks.Looks = NEW [TextLooks.Looks ¬ TextLooks.noLooks];
FOR pairs: AtomList ¬ def.rest, pairs.rest.rest WHILE pairs # NIL DO
attribute: ATOM = pairs.first;
value: ATOM = pairs.rest.first;
Bitch: PROC = {
permMessage.PutFL["Can't cedarize %a=%a on look %a from dictionary %a --- will underline instead\n", LIST[[atom[attribute]], [atom[value]], [atom[dictLook]], [atom[dictionary]]] ];
cedarLooks['z] ¬ TRUE;
};
SELECT attribute FROM
$FAMILY => SELECT value FROM
$TIMESROMAN => NULL;
$HELVETICA => cedarLooks['o] ¬ TRUE;
$HIPPO => cedarLooks['g] ¬ TRUE;
ENDCASE => Bitch[];
$SIZE => {
size: INT = Convert.IntFromRope[Atom.GetPName[value]];
SELECT size FROM
<10 => cedarLooks['s] ¬ TRUE;
=10 => NULL;
>12 => cedarLooks['x] ¬ TRUE;
ENDCASE => cedarLooks['l] ¬ TRUE;
};
$FACE => SELECT value FROM
$STANDARD => NULL;
$BOLD => cedarLooks['b] ¬ TRUE;
$ITALIC => cedarLooks['i] ¬ TRUE;
$BOLDITALIC => cedarLooks['b] ¬ cedarLooks['i] ¬ TRUE;
ENDCASE => Bitch[];
$SUPERSCRIPT => cedarLooks['u] ¬ TRUE;
$SUBSCRIPT => cedarLooks['d] ¬ TRUE;
ENDCASE => Bitch[];
ENDLOOP;
IF cedarLooks['d] OR cedarLooks['u] THEN cedarLooks['s] ¬ FALSE;
IF NOT RefTab.Store[looksTranslator, dictLook, cedarLooks] THEN ERROR;
ENDLOOP;
};
PutNode: PROC [stream: STREAM, node: Tioga.Node, start: INT ¬ 0, len: INT ¬ INT.LAST] ~ {
prevLooks: Tioga.Looks ~ IOTioga.GetLooks[stream];
IF node.runs=NIL THEN {
IOTioga.SetLooks[stream, Tioga.noLooks];
IO.PutRope[stream, node.rope, start, len];
}
ELSE {
index: INT ¬ start;
action: Rosary.RunActionType ~ {
looks: Tioga.Looks ~ TextEdit.LooksFromItem[item];
IOTioga.SetLooks[stream, looks];
IO.PutRope[stream, node.rope, index, repeat];
index ¬ index+repeat;
};
[] ¬ Rosary.MapRuns[[base: node.runs, start: start, size: len], action];
};
IOTioga.SetLooks[stream, prevLooks];
};
PutWithRuns: PRIVATE PROC [to: IO.STREAM, rope: ROPE, dictRuns: Dictionary.RunList] = {
node: Tioga.Node ¬ TextEdit.FromRope[rope];
FOR drs: Dictionary.RunList ¬ dictRuns, drs.rest WHILE drs # NIL DO
dr: Dictionary.RunPointer = drs.first;
cedarLooks: REF TextLooks.Looks ¬ NARROW[RefTab.Fetch[looksTranslator, dr.font].val];
IF dr.length = 0 THEN LOOP;
IF cedarLooks = NIL THEN {
to.PutF["Got unexpected look %a (from dictionary %a) --- will use underlining\n", [atom[dr.font]], [atom[dictionary]]];
cedarLooks ¬ unexpectedLooks;
};
TextEdit.ChangeLooks[root: node, text: node, add: cedarLooks­, start: dr.start + dOrigin, len: dr.length];
ENDLOOP;
PutNode[to, node];
};
dOrigin: INT ¬ -1 --add this to dictionary's origin to get Cedar's origin--;
unexpectedLooks: REF TextLooks.Looks ¬ NEW [TextLooks.Looks ¬ TextLooks.RopeToLooks["z"]];
PutCourierError: PROC[out: STREAM, exp: ROPE] ~
{ IO.PutF1[out, "Unable to connect to dictionary server %g\n", [rope[exp]] ] };
PutServiceError: PROC[out: STREAM, exp: ROPE] ~
{ IO.PutF1[out, "The dictionary server is down %g\n", [rope[exp]] ] };
}.