Recent Changes - Search:

WikiDoc

Categories

Spell checking

Features.SpellChecking History

Hide minor edits - Show changes to markup

October 16, 2007, at 03:48 PM by agm - spam cleanup
Deleted line 0:

rollidel

Changed line 37 from:

discussed on the MacOSX-TeX mailing list, and also on Alpha-D. Frédéric

to:

discussed on the MacOSX-TeX mailing list, and also on Alpha-D. Fr√d√ric

October 16, 2007, at 03:12 PM by 74.231.24.2 -
Added line 1:

rollidel

Changed line 38 from:

discussed on the MacOSX-TeX mailing list, and also on Alpha-D. Fr√d√ric

to:

discussed on the MacOSX-TeX mailing list, and also on Alpha-D. Frédéric

January 23, 2006, at 03:39 PM by 212.180.15.164 -
Added lines 1-436:

(:title Spell checking:)

Some possibilities

Under OS9, Spellchecking in Alpha was synonymous with 'Excalibur' http://www.eg.bucknell.edu/~excalibr/excalibur.html. Excalibur is LaTeX aware and has a very clean user interface. Interaction with Excalibur works the same under OSX.

Under OSX there are some other possibilities.

One is perhaps OSX's built-in spellchecker using Services --- does this work?

Another possibility is using the Cocoaspell service. I don't know how well that works.

Standard Alpha Aspell checking

Another possibility (which is currently the main subject of this page) is interaction with the UNIX command-line spellchecker 'aspell' (and also 'ispell' --- is there any particular reason to use ispell? It seems that aspell pretends to replace ispell...). One convenient way of installing aspell in OSX is via fink http://fink.sourceforge.net.

The current AlphaTcl library has good support for interaction with aspell, to spellcheck the frontmost window or just the selection. The spellchecking takes place inside Alpha while aspell operates behind the scenes (through a pipe). Suggestion and replacement of corrected words are handled in the status bar. Perhaps there is room for improvements with respect to interaction also with aspell dictionaries (user dictionary and corrections database), but it might actually already be in place --- not too sure.

(It would be very nice to implement some sort of language switch, a little tag to tell aspell to switch to a given dictionary. This has been discussed on the MacOSX-TeX mailing list, and also on Alpha-D. Fr√d√ric proposed some tags, also for much more general purposes, but right now I can't find that message.)

Check as you type

There is also an experimental check-as-you-type spellchecker, also using aspell as its engine. Here your typing is monitored and every word is sent to aspell. Words found not to be correct are underlined and coloured red, and in a separate little window the suggestions appear. For the time being this is just a prototype --- no particular effort has been made to streamline the set-up or the interface --- but the core functionality seems to work alright. Instructions, code, download link, and a few comments can be found below.

The rest of this page is mostly concerned with technical details.


The standard interaction with aspell is implemented using pipes, and it is a very instructive example of setting up pipes. The file spellcheck.tcl also contains a lot of information about aspell (taken from the aspell manual).

(Anonymous) remark copied over from the page [AlphaTcl and Helpers]: [[the code of the tex interface in newComm.tcl]] is pretty similar to the interactive spell-checker which is used by Alphatk on Windows (in Tcl/SystemCode/CorePackages/spellcheck.tcl). I'm sure we can move some common 'pipe' functionality into AlphaTcl.

<JK 20/09/2003>: no coincidence --- newComm.tcl learned about pipes from spellcheck.tcl. Later it turned out there is a lot of instructive examples of pipes over at the TclTk wiki and it is also very well explained in Bernard's wonderful book Tcl/Tk http://webperso.easyconnect.fr/bdesgraupes/books.html#tck (in French). It is all pretty much the same. I think the conclusion is that this is simply how pipes work in Tcl...

I have tried to write a short introduction to pipes (with a stripped-down example) on the page Pipes.PipesAndShellLikeInteraction. See also Pipes.BatchLikeInteractionViaPipes.

'pipe API'

Vince has defined an API for line-based pipe interaction. It is currently used in the standard aspell spellchecker and in the alternative interactive tetex interface altComm. There is already support for features and options beyond what these two examples need.


Check-as-you-type spellchecker prototype

You can also download this from http://www.cirget.uqam.ca/~kock/alpha-tcl/spell.tcl.gz .

<JK 31/07/2003>:

 
    # -------------------------------------------------------------------------
    # Check-as-you-type spell-checker for Alpha, using aspell.
    # (To install aspell on your machine, the easiest way is
    # probably  fink <http://fink.sourceforge.net>.)
    # 
    # This is just a prototype --- no particular effort has been
    # made to streamline the set-up or the interface...
    # 
    # To toggle the spell-checker, press F2.
    # 
    # To perform corrections on the basis of a suggestions list,
    # do Ctrl-K followed by the index of the correction.  This
    # works for the suggestions currently shown, independent of
    # cursor position.  
    # -------------------------------------------------------------------------



    # Global variables read by all the procs
    # 
    # these are assembled into the array aspRec
    # 
    # key          the current word
    # p0 p1        the position of the current word
    # sug          the suggestions for the current word
    # 
    # mainWin      the name of the window where the current record is valid
    #              is recorded at the moment any suggestions are displayed,
    #              so that subTypo later can know which window these suggestions
    #              belong to
    # 
    # doSetlink    0/1  whether misspelled word should be underlined
    #              when a word is automatically detected wrong then it should
    #              be underlined.  If we just click on an already underlined word 
    #              then it should not...
    # pipeName     the id of the pipe to aspell

    Bind F2 toggleSpellCheck
    newPref f spellCheckOn 1
    newPref f doSuggest 1
    # doSuggest    whether the output from aspell should be displayed
    #              while typing

    set spellCheckOn 0

    proc toggleSpellCheck {} {
	global spellCheckOn
	global aspRec
	if { $spellCheckOn } {
	    set spellCheckOn 0
	    closeAspell
	} else {
	    set spellCheckOn 1
	    openAspell
	}
    }

    proc openAspell {} {
	global aspRec doSuggest
	set aspRec(pipeName) [open "|/sw/bin/aspell --sug-mode=ultra pipe" RDWR]
	fconfigure $aspRec(pipeName) -buffering line -translation auto -blocking 0
	after 1000
	set status [catch { gets $aspRec(pipeName) aspRec(sug) } result]
	if {$status == 0 && $result >= 0} {
	    # it's ok
	    if { $doSuggest } {
		showSuggestions
	    }
	    status::msg "$aspRec(sug)"
	    puts $aspRec(pipeName) "!"  
	} else {
	    close $aspRec(pipeName)
	    alertnote "Spellcheck failed: $result"
	}
	fileevent $aspRec(pipeName) readable listenToAspell
	Bind 0x31 monitorTyping "Text"
    }


    proc closeAspell {} {
	global aspRec
	catch { close $aspRec(pipeName) }
	unBind 0x31 monitorTyping "Text"
	if { ![catch {bringToFront "* Console (suggestions) *"}] } {
	    killWindow
	}
	catch { removeColorEscapes }
	refresh
	status::msg "Spell check off"
    }


    proc monitorTyping { } {
	global aspRec
	insertText " "
	# What to look up?  --- is there an open window?:
	if { ![catch {set pos [getPos]}] } { 
	    if { [isSelection] } {
		deleteSelection 
	    }
	    backwardWord 
	    set aspRec(p0) [getPos]
	    forwardWord
	    set aspRec(p1) [getPos]
	    set aspRec(key) [getText $aspRec(p0) $aspRec(p1)]
	    goto $pos
	}
	set aspRec(doSetlink) 1
	# Write to aspell
	puts $aspRec(pipeName) "^$aspRec(key)"
    }



    proc check { word } {
	global aspRec
	# We only come in here when called from a colour link.
	# In that case the values of key, p0, p1 are outdated,
	# so we have to quickly reconstruct them.  We know where
	# we are, because the mouse is over the link!:
	catch { 
	    set mPos [mousePos]
	    set pos [eval pos::fromRowCol $mPos]
	    # Find $word on this line:
	    set posPair [search -f 1 -r 0 -s -- $word [lineStart $pos]]
	    set aspRec(p0) [lindex $posPair 0]
	    set aspRec(p1) [lindex $posPair 1]
	}
	set aspRec(key) $word   
	set aspRec(doSetlink) 0
	# Write to aspell
	puts $aspRec(pipeName) "^$aspRec(key)"
    }

    proc listenToAspell { } {
	global aspRec doSuggest
	set status [catch { gets $aspRec(pipeName) aspRec(sug) } result]
	if { $status || $result < 0} { 
	    alertnote "Something went wrong with the pipe"
	    set spellCheckOn 0
	    closeAspell
	    return
	}
	if { $aspRec(doSetlink) } {
	    switch  -- [string index $aspRec(sug) 0] {
		"&" {
		    setLinkHere
		    if { $doSuggest } {
			showSuggestions
		    }
		}
		"#"  {
		    setLinkHere
		}
	    }
	} else {
	    # If we don't set link, then independent of global var we do:
	    showSuggestions
	}
	gets $aspRec(pipeName) "" ;# just to get rid of what junk there might be left?!
    }


    proc setLinkHere {} {
	global aspRec
	text::color $aspRec(p0) $aspRec(p1) 4
	text::hyper $aspRec(p0) $aspRec(p1) "check $aspRec(key)"
	refresh
    }



    # When showSuggestions is called, the current window is recorded as 'main'.
    # Later substitutions will apply to this mainWin.
    proc showSuggestions {} {
	global aspRec
	set aspRec(mainWin) [win::CurrentTail]

	regsub {\& ([\w]+) [0-9]+ [0-9]+: } $aspRec(sug) "0:  \\1\r---------\r1:  " aspRec(sug) 
	set i 2
	while { [regsub {, } $aspRec(sug) "\r$i:  " aspRec(sug)] }  { 
	    incr i 
	}
	set winName "* Console (suggestions) *"
	if { [catch { replaceText -w $winName [minPos] [maxPos -w $winName] "$aspRec(sug)"}] } {
	    new -g 611 44 234 300 -n $winName -m Shel -shell 1
	    replaceText -w $winName [minPos] [maxPos -w $winName] "$aspRec(sug)"
	    bringToFront $aspRec(mainWin)
	}
    }




    ##############################################################

    proc subsTypo { num } {
	global aspRec
	bringToFront $aspRec(mainWin)
	text::color $aspRec(p0) $aspRec(p1) 0
	text::hyper $aspRec(p0) $aspRec(p1) ""
	if { $num != 0 } {
	    set pos [search -w "* Console (suggestions) *" -f 1 -r 1 -s "$num:\\s+(\\S+)\\s+" [minPos]]
	    set txt [eval getText -w "\"* Console (suggestions) *\"" $pos]
	    regexp -- "$num:\\s+(\\S+)\\s+" $txt "" txt
	    replaceText -w "$aspRec(mainWin)" $aspRec(p0) $aspRec(p1) $txt
	}
	refresh
    }

    Bind    'k'    <z> prefixChar 
    for { set i 0 } { $i < 10 } { incr i } {
	eval Bind '$i' <K> \{ subsTypo $i \}
    }

    # 
    # 
    # 
    # 
    # 
    # set typoList [list ]
    # # we ought to have a list for each window...
    # 
    # 
    # 
    # 
    # proc subsTypo { num } {
    #     global suggestionsList 
    #     global typoList
    #     
    #     set key [lindex $suggestionsList 0]
    #     set colorList [getColors]
    #     set i [llength $colorList]
    #             incr i -1
    #     while { ![regexp $key [lindex [lindex $colorList $i] 2]] } {
    #         incr i -1
    #     }
    # #     alertnote "[lindex $colorList $i]"
    # #     set i [lsearch -regexp $colorList $key]
    #     set p0 [lindex [lindex $colorList $i] 0]
    #     set p1 [pos::math $p0 + [string length $key]]
    #       text::color $p0 $p1 0
    #       text::hyper $p0 $p1 ""
    #     
    #     replaceText $p0 $p1 [lindex $suggestionsList $num]
    # #     refresh
    #     
    #     #pop the typoList: actually we shouldn't just pop it: we should
    #     #delete exactly the entry we fixed... 
    #     set j [lsearch -exact $typoList $key]
    #     set typoList [lreplace $typoList $j $j ]
    #     if { [set l [llength $typoList]] > 0 } {
    #       getSuggestions [lindex $typoList [expr  $l -1]]
    #       displaySuggestions
    #     } else {
    #       removeColorEscapes
    #     }
    #     
    #   
    # }

Comments from Joachim: I am not working on this any more. I think it works well enough to spellcheck short emails and such, while you type them. Some problems and todo items:

It ought to be like this: when you correct a word (choosing from the suggestions list) you get the suggestions list of the previous misspelled word. In this way you can work your way backwards in the document until all errors are corrected or you don't care anymore for now. The reason for working backwards is that your memory is a stack, not a queue: certainly the first word you want to correct is the one you just typed, and the red underline has just appeared, and you have just finished the sentence you were typing and then you want to correct the word. So it makes sense that the suggestion window should always show the suggestions pertaining to the latest error. Consequently, the direction of correction progress is backwards in the document.

Note that the cursor postion does not change when you correct a word. In this way you can easily correct the last couple of errors and continue typing without need for cursor movement.

If you wanted to correct the errors systematically from the beginning of the document to the end, you would use the document-based spellchecker instead.

Problem: there seems to be some problems with Alpha's hypertext facilities: if you remove or insert colour escapes before another colour escape it can break --- I can't remember the exact problem, but it was one of the reasons I stopped working on this... (a shame I didn't supply a bug report.

Peculiarity (AlphaX rendering problem): in the moment a colour escape is inserted at a misspelled word (this happens in the moment you press <space>) a shade of the cursor remains at the word boundary. This shade is like a static vertical non-blinking line, and it remains there for some time (not preventing the usual blinking cursor to move forward with your typing...)


A few more comments from Alpha-D:

Gianguido: It's great, but only for newly opened pure text files. I mean it doesn't work with latex or else...

Joachim: Actually it can work in any mode, but as you point out, the version I posted only enables checking in Text mode --- this was merely for convenience while debugging and programming...

To enable it in other modes, remove "Text" from the line

 
    Bind 0x31 monitorTyping "Text"

(and similarly in the unBind statement a little later).

Check-as-you-type works best in pure text modes like Text and Mail. Obviously it would be great to get it to work in TeX and HTML modes, but it would require some on-the-fly parsing, and I didn't have the energy or expertise to attack this problematic... (And I don't know if such things exist in other check-as-you-type capable editors...) I mean, we wouldn't like to flag anything between dollar signs, and to determine whether a word is in math mode or not it would be necessary to count all the dollar signs in the paragraph, and there are many other structures that should be taken into account. All this is much easier on a document basis than on a single-word basis (cf. Excalibur and also aspell). In HTML mode it will perhaps be easier, since the only question would be to check whether the current word is inside a < > pair or not --- perhaps such tools are already in HTML mode, Johan?


Category.Features

Page last modified on October 16, 2007, at 03:48 PM
Hosted on SourceForge.net Logo