Home, End and other formatting problems

unperson I encounter a serious problem on a TCL/TK application. When I click on "Home", the cursor goes to the beginning of the paragraph and not to the beginning of the line. The same with the "End" key. It goes to the end of the paragraph and not to the end of the line.

Finally, to top it all off, when I use the up or the down arrows, they don't move the cursor to the line above or below; they move it to the line where the paragraph starts or ends.

What causes this serious and very painful problem? What do I do to fix it? Thanks!

NEM: Wait for Tk 8.5 (or use an alpha release): TIP 155[L1 ] provides the functionality you need, AIUI. (BTW, it's not generally a good idea to use this wiki for questions, and less so to create a new page for a single question. news:comp.lang.tcl is a better place for such queries.)

unperson I will. Thanks so much Neil. I went on your homepage and I was impressed at the diversity of projects you got involved in. True inventors (like you) touch a lot of everything before they come up with the one excellent idea that will revolutionize the world. Keep it up Doctor Madden! Well not quite Doctor yet; in a few months from now you will be able to use this title! When that happens, you'll be astonished at the people who will call you to come cure them... A doctor is still seen as many as the man with a stethoscope! :-)

MG Jan 27th 2005 - The page Move cursor by display line in a text widget also shows a pure-Tcl way to fix this in 8.4, which may be better for now, as many people aren't using 8.5 yet. One thing this doesn't fix, however, is the Control-Up / Control-Down bindings (for going to the beginning of the previous/next paragraph).

unperson Thanks MG. It seems that the program does not seem to see an end of line and it can only see this when a return has been made. It thus treats a series of lines as one single line!

Please don't tell me that this sort of problem can only be solved in a latter version of TCL! This is such a basic feature that I fail to see how this problem could not have been addressed very early on! Tell me I am mistaken!

wdb 2005/05/16 -- I happen to have a solution for Tcl/Tk <= 8.4, described at Ask, and it shall be given # 3, solution at [L2 ].

MG Feb 5th 2005 - It's the way that the text widget is coded internally that causes the problem. There's no way to get around it before Tcl 8.5, other than by recoding the text widget bindings; internally, the text widget just doesn't support display lines sufficiently. So, I'm afraid you'll either have to use alternative bindings every time you need it, or wait for 8.5.

LV Actually, the above comments refer to the Finally portion of your question. Which platforms show the Home and End behavior? On SPARC Solaris GNOME, I see the opposite behavior. What's interesting though is that I would have expected HOME to take me to the top of the file and End to take me to the last line of the file.

Normally, I'd expect Control-A to take one to the beginning of the line and Control-E to the end line.

LES: Sure, you are an emacs addict. A vi addict could reasonably expect ^ to take one to the beginning of the line and $ to the end of the line. So, instead of hard-coding these things with key bindings, perhaps the new improvements should concentrate on events only. Then it's up to each developer to decide which key binding will trigger each one of those specific events. And, just for the record, Move cursor by display line in a text widget really solves the problem described at the top of this page, but it kills Control + Home.

MG Normal behaviour as I'd expect it (bearing in mind I'm a clueless Windows user:) is for Home/End to do the beginning/end of a line, and Control + Home/End to do the beginning/end of the document. As far as I can recall, there isn't usually any way in Windows apps to do "start of the paragraph" with the Home/End keys.

unperson Yes you are right, Mike. That is the way it works in Windows

LV Turns out that because of the fix via the Page above, the Home and End keys were working 'correctly for me as described above. If I removed the change, the behavior went back to the broken behavior originally described.

unperson 8.5 sure fixes the Home/End problem but it creates a whole lot of other problems along the way. When I use tcl kit 8.5 with a TCL editor I have had programmed (working with Windows 98), I get error messages all the time for almost every task required! The error message is always "the program has performed an illegal function and will be terminated". And boum I am out of the program. It's pretty frustrating. :-(

I'd rather not use 8.5 at this stage for the cure seems to bring more problems than the disease so does anyone have an idea how to solve the Home/End keys problem without upgrading to 8.5? -- yes, look here: [L3 ]

LV It seems like somehow the code mentioned above might be able to be refactored somehow by someone more familar with Tk than I so that one could create some new functions that could be placed into binds . I've just not been able to figure out how to do this.

Vince well, if Tcl/Tk 8.5 keep crashing for you, perhaps you should submit a bug report giving reproducible circumstances for the developers so the bug can be fixed... I find 8.5 incredibly stable for my uses.

LV Vince, I'm with you. I've been using 8.5 on Solaris for several years and have never found a problem. Robert, is it possible that you got a wrong binary for 8.5?

unperson Could very well be. Thanks Vince and LV. I'll try the other binary. (I had the UPX one before). Thanks!

I see that the TCL Kit 8.5 comes without a library whereas the previous ones did. I copied the old library and I inserted it in the tcl kit 8.5 sub-directory. I still get errors.

Does anyone have some experience with the TCL Kit 8.5 running with Windows 98? Can you tell me if it works well for you? Thanks!

Vince The tclkit you are using is, most likely, from December 2004 or at best January 2005 (since I think that's the latest one jcw has built). Tcl/Tk 8.5 has had numerous fixes since then. If you are using 8.5 you should probably be using a more recent version (which you will therefore have to build yourself, or ask someone else to, unfortunately). Having said that, I'm only running on Win2000, WinXP, so no idea about Win98.

LV Ah, Robert, I wasn't aware that you were still using Windows 98; alas, like Vince, I've no idea whether that causes problems. I thought that Tcl/Tk no longer supported the Windows 98 family of OSes...


(MG - Moved from my personal page, Wed Apr 27 2005)

From unperson

Hi Mike! I have been using an old version of tcl kit with my editor and I seem to have no problems with it. We managed to fix the cursor problem and now the cursor is going to the next line as it should.

I tried the 8.5 tcl kit for Windows and I have lots of problems with Windows 98.

Do you have any idea how to fix the Home/End problem using the old version of TCL Kit (without having to upgrade to TCL 8.5? Thanks!

See here: https://wiki.tcl-lang.org/13418

MG I've dug out the code I used once from Potato MUSH (MUD) Client and put it on my website as a package (just wiki-style, at the moment - you can view it, and copy/paste it off, but not download, atm). Just copy both files down into someplace on your auto_path, then

 package require textbind
 ::textbind::setup 1

to use it. (Use ::textbind::setup 0 if you don't want a new binding for Control-A that does "Select All" - that's very Windows-y, I think, and the reason the setup isn't done as part of the package require.) All the bindings on the Text widget for Home/End, Left/Right, Up/Down (and associated Control/Shift bindings) will be edited. Should work OK on Tk 8.3 and 8.4. Anything before that is a gamble, but you're welcome to try, if you're still using those. You can get the code here: [L4 ]

unperson Mike, you're very helpful as usual. I'll try this code and I'll keep you informed. Again, many thanks!

unperson Well almost a year later -to the day. The bug has been fixed even on my editor and the fix works even on Windows 98, to boot! Wow! It's a new day in my life!

A million thanks to all the teclers who participated to this page and gave excellent advice: MG, NEM, LES, LV and Vince.

Mike Griffiths, you are a pro!


(Moved from: Ask, and it shall be given # 4)

Ravi Christianosk Have d'loaded a TCL editor and I seem to have problems with the cursor; when I click Home I get to the beginning of the paragraph instead then the beginning of the line. Vice-versa: end gets me to the end of the paragraph. When I wanna an ascii code, I get the code 3 pages down instead of the location of the cursor. What seems to be the problem and how to fix it?

wdb That is a matter of key binding:

 % bind Text <Home>

    tkTextSetCursor %W {insert linestart}

 % bind Text <End>

    tkTextSetCursor %W {insert lineend}

Solution: change the binding of the tag Text to some other script such that cursor goes to start/end of screen line.

Example:

 bind Text <Home> {tk::TextSetCursor %W [textPos1Dline %W]}
 bind Text <Shift-Home> {tk::TextKeySelect %W [textPos1Dline %W]}
 bind Text <Up> {tk::TextSetCursor %W [textUpDLine %W]}
 bind Text <Shift-Up> {tk::TextKeySelect %W [textUpDLine %W]}
 bind Text <Down> {tk::TextSetCursor %W [textDownDLine %W]}
 bind Text <Shift-Down> {tk::TextKeySelect %W [textDownDLine %W]}
 bind Text <End> {tk::TextSetCursor %W [textEndDline %W]}
 bind Text <Shift-End> {tk::TextKeySelect %W [textEndDline %W]}
  
 proc textUpDLine {widget} {
    # Return index of position visually above insert.
    # Scroll if necessary.
    $widget see insert
    if {[$widget dlineinfo insert] == [$widget dlineinfo 1.0]} {
        return [$widget index insert]
    }
    set bbox [$widget bbox insert]
    if {[string equal $bbox ""]} {
        set x 0
    } elseif {[$widget get insert] == "\n"} {
        set x [expr {[lindex $bbox 0] + [lindex $bbox 3] / 4}]
    } else {
        set x [expr {[lindex $bbox 0] + [lindex $bbox 2] / 2}]
    }
    set lbox [$widget dlineinfo insert]
    set y [lindex $lbox 1]
    if {$y < 5} {
        $widget yview scroll -1 units
        set lbox [$widget dlineinfo insert]
        set y [lindex $lbox 1]
    }
    incr y -1
    # return this value:
    $widget index @$x,$y
 }
 
 proc textPos1Dline widget {
    # return start index of line containing insert.
    $widget xview moveto 0
    set dline [$widget dlineinfo insert]
    set beginX [lindex $dline 0]
    set beginY [lindex $dline 1] 
    # return this value:
    $widget index @$beginX,$beginY
 }
 
 
 proc textEndDline widget {
    # return end index of line containing insert.
    set dline [$widget dlineinfo insert]
    set endY [lindex $dline 1]
    set endX [lindex $dline 0]
    incr endX [lindex $dline 2]
    set tooWide [expr {$endX > [winfo width $widget]}]
    if {$tooWide} {
        $widget xview moveto 1
    } else {
        $widget xview moveto 0
    }
    set index [$widget index @[winfo width $widget],$endY]
    $widget see $index
    return $index
 }
 
 proc textDownDLine {widget} {
    # Return index of position visually below insert.
    # Scroll if necessary.
    $widget see insert
    if {[$widget dlineinfo insert] == [$widget dlineinfo end-1chars]} {
        return [$widget index insert]
    }
    set bbox [$widget bbox insert]
    if {[string equal $bbox ""]} {
        set x 0
    } elseif {[$widget get insert] == "\n"} {
        set x [expr {[lindex $bbox 0] + [lindex $bbox 3] / 4}]
    } else {
        set x [expr {[lindex $bbox 0] + [lindex $bbox 2] / 2}]
    }
    set lbox [$widget dlineinfo insert]
    set y [lindex $lbox 1]
    incr y [lindex $lbox 3]
    incr y 5
    if {$y > [winfo height $widget]} {
        # scrollDown
        $widget yview scroll 1 units
        set lbox [$widget dlineinfo insert]
        set y [lindex $lbox 1]
        set dy [lindex $lbox 3]
        incr y $dy
        incr y 5
    }
    # return this value:
    $widget index @$x,$y
 }