Version 13 of Linux Console Text Editor In Pure TCL

Updated 2005-05-04 22:32:21 by JH

2004-06-16 SRIV This is a minimal console text editor for Linux written in pure TCL.

Usage: con-editor.tcl filename After the file loads, the screen is blank till you hit the down arrow key, I forget why I did that. To save the file, press Ctrl-Q, it will prompt you to Save Y/n . Ctrl-Y will delete the current line.

I notice that the backspace key isn't working properly on my current computer, so I'll need to look into that. Update: backspace works at a true console, but misbehaves in an xterm. It also is fixed at 24x80, so the editor wont use more that that, like on a 50x132 framebuffer system.

Edited by JH 2005-05-04 to support any size terminal and clean up the code for improved readability. Anyone wanting to interpret more escape codes should find it easier to work with.

Screenshot:

http://www.sriv.net/images/con-editor.jpg


 #!/bin/sh
 # The next line is executed by /bin/sh, but not tcl \
     exec tclsh "$0" ${1+"$@"}

 # con-editor.tcl a linux console based editor in pure tcl
 # 2004-06-16 Steve Redler IV
 # 2005-05-04 mods by Hobbs to work in any terminal size and clean up code
 set filename [lindex $argv 0]

 proc edittext {file2read visible} {
     global CLEAR buffer HOME CURSOROFF CURSORON IDX

     set COLUMN 1
     set ROW 1
     set lastrow ""
     set lastcol ""
     set firstcol2display ""
     set firstrow2display ""
     set line ""
     set bufferrow  0
     set buffercol 0
     set char ""
     puts -nonewline $CURSOROFF$HOME

     while {$char != "\u0011"} {
         set char [read $file2read 1]
         if {[eof $file2read]} {return done}

         switch -exact -- $char {
             \u0011 { # ^q - quit
                 return done
             }
             \u0019 { # ^y - yank line
                 if {$bufferrow < [llength $buffer]} {
                     set buffer [lreplace $buffer $bufferrow $bufferrow]
                     set lastcol ""
                 }
             }
             \u000a { # ^j - insert last yank
                 set currline [string range $line 0 [expr {$buffercol - 1}]]
                 set buffer [lreplace $buffer $bufferrow $bufferrow $currline]

                 if {!$visible} {set IDX(ROW) $bufferrow}
                 incr bufferrow
                 incr ROW
                 set buffer [linsert $buffer $bufferrow \
                                 [string range $line $buffercol end]]
                 set lastcol ""
                 set line [lindex $buffer $bufferrow]
                 set buffercol 0
             }
             \u001b { # ESC - handle escape sequences
                 set next [read stdin 1]
                 if {$next == "\["} { ; # \[
                     set next [read stdin 1]
                     switch -exact -- $next {
                         A { # Cursor Up (cuu1,up)
                             if {$bufferrow > 0} {incr bufferrow -1}
                             set line [lindex $buffer $bufferrow]
                             incr ROW -1
                         }
                         B { # Cursor Down
                             if {$bufferrow < [expr {[llength $buffer] -1}]} {
                                 incr bufferrow 1
                             }
                             set line [lindex $buffer $bufferrow]
                             if {$bufferrow > [expr {$ROW -1}]} { incr ROW }
                         }
                         C { # Cursor Right (cuf1,nd)
                             if {$buffercol < [string length $line]} {
                                 incr buffercol 1
                             }
                         }
                         D { # Cursor Left
                             if {$buffercol > 0} {incr buffercol -1 }
                         }
                         3 { # delete
                             set next [read stdin 1]
                             if {$buffercol > [string length $line]} {
                                 set buffercol [string length $line]
                             }
                             set prevchr $buffercol
                             set line [string replace $line $prevchr $prevchr ""]

                             set buffer [lreplace $buffer $bufferrow  $bufferrow  $line]
                             set lastcol ""
                         }
                     }
                 }
             }

             \u007f { # backspace ?
                 if {$buffercol != 0} {
                     if {$buffercol > [string length $line]} {
                         set buffercol [string length $line]
                     }
                     set prevchr [expr {$buffercol - 1}]
                     set line [string replace $line $prevchr $prevchr ""]
                     incr buffercol -1
                 }
                 set buffer [lreplace $buffer $bufferrow  $bufferrow  $line]
                 set lastcol ""
             }

             default {
                 if {$char == "\u0009"} { # ^i - insert tab space (4 spaces)
                     set char "    "
                 }
                 append newline [string range $line 0 [expr {$buffercol - 1}]] \
                     $char [string range $line $buffercol  end]
                 set line $newline
                 set newline ""
                 set buffer [lreplace $buffer $bufferrow  $bufferrow  $line]
                 incr buffercol [string length $char]
                 if {$buffercol > [string length $line]} {
                     set buffercol [string length $line]
                 }
                 set lastcol ""
             }

         }
         if {$visible} {
             if {$ROW <= 1} {set ROW 1}
             if {$ROW >= ($IDX(ROWMAX) - 1)} {set ROW [expr {$IDX(ROWMAX) - 1}]}
             set COLUMN [expr {$buffercol + 1}]
             if {$COLUMN <= 1} {set COLUMN 1}
             if {$COLUMN >= $IDX(COLMAX)} {set COLUMN $IDX(COLMAX)}

             puts -nonewline $CURSOROFF$HOME

             set firstrow2display [expr {$bufferrow - $ROW  +1}]
             set lastrow2display  [expr {$firstrow2display + $IDX(ROWMAX) - 1}]
             set firstcol2display [expr {$buffercol - $COLUMN +1}]
             set lastcol2display  [expr {$firstcol2display + $IDX(COLMAX) - 1}]

             if {($lastrow != $firstrow2display)
                 || ($lastcol != $firstcol2display)} {
                 for {set i $firstrow2display} {$i < $lastrow2display} {incr i} {
                     puts -nonewline "\u001b\[K"
                     puts [string range [lindex $buffer $i] $firstcol2display $lastcol2display ]
                 }
             }

             set lastrow $firstrow2display
             set lastcol $firstcol2display
             set IDX(ROW) [expr {$bufferrow +1}]
             set IDX(COL) [expr {$buffercol +1}]

             idx $IDX(ROW) $IDX(COL)

             puts -nonewline "\u001b\[${ROW};${COLUMN}H"
             puts -nonewline $CURSORON
             flush stdout
         }
     }
 }

 proc status {msg} {
     global IDX
     set len [expr {$IDX(ROWCOL) - 1}]
     set str [format "%-${len}.${len}s" $msg]
     puts -nonewline "\u001b\[$IDX(ROWMAX);00H$str"
 }

 proc idx {row col} {
     global IDX
     set len $IDX(ROWCOLLEN)
     set str [format "%-${len}.${len}s" "LINE:$row COL:$col"]
     puts -nonewline "\u001b\[$IDX(ROWMAX);$IDX(ROWCOL)H$str"
 }

 #start of console editor program
 #puts -nonewline $CLEAR

 proc console_edit {fileName} {
     global CLEAR buffer HOME CURSOROFF CURSORON IDX
     #Script-Edit by Steve Redler IV   [email protected]    5-30-2001

     set IDX(ROWMAX) 24
     set IDX(COLMAX) 80
     if {![catch {exec stty -a} err]
         && [regexp {rows (\d+); columns (\d+)} $err -> rows cols]} {
         set IDX(ROWMAX) $rows
         set IDX(COLMAX) $cols
     }
     set IDX(ROWCOLLEN) 15
     set IDX(ROWCOL) [expr {$IDX(COLMAX) - $IDX(ROWCOLLEN)}]

     set CLEAR     "\u001b\[2J" ; # \u001b == ESC
     set buffer    [list {}]
     set HOME      "\u001b\[1;1H"
     set CURSORON  "\u001b\[?[expr {$IDX(ROWMAX)+1}]h"
     set CURSOROFF "\u001b\[?[expr {$IDX(ROWMAX)+1}]l"

     set infile [open $fileName RDWR]
     edittext $infile 0
     close $infile

     puts -nonewline $CLEAR$HOME$CURSORON
     status "\u0007$fileName loaded"
     idx $IDX(ROW) 1

     fconfigure stdin -buffering none -blocking 1
     fconfigure stdout -translation crlf

     flush stdout
     exec stty raw -echo
     edittext stdin 1
     status "Save '$fileName'? Y/n"
     flush stdout
     #fconfigure stdin -buffering full -blocking 1
     set line [read stdin 1]
     exec stty -raw echo
     if {$line != "n"} {
         set outfile [open $fileName w ]
         puts "len of buffer [llength $buffer]"
         for {set i 0} {$i<[llength $buffer]} {incr i} {
             puts $outfile [lindex $buffer $i]
             #puts  [lindex $buffer $i]
         }
         close $outfile
         status " Saved"
     } else {
         status " Aborted"
     }

     puts -nonewline $CLEAR$HOME
     exit 0
 }

 console_edit $filename

Category Application