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]] ] };
}.