tk-latex-editor/lib/modules/editor.tcl

675 lines
24 KiB
Tcl
Executable File

#########################################################
# TkTeXeditor
# Distributed under GNU Public License
# Author: Sergey Kalinin (BanZaj) banzaj@lrn.ru
# Copyright (c) "CONERO lrn", 2000, http//conero.lrn.ru
#########################################################
## FILE EDITOR WINDOW ##
proc EditFile {file} {
global dir font tree nb files color files index status activeFile treeStruct ver
global editor backup status replace sysenc release
wm title . "TkLaTeXEditor $ver$release - $file"
if {[file exists $file] == 0} {
set answer [tk_messageBox -message "$f [::msgcat::mc "File not found"]"\
-type ok -icon warning -title [::msgcat::mc "Warning"]]
case $answer {
ok {return}
}
}
set fileName [file tail $file]
set fileDir [file dirname $file]
set dir(current) $fileDir
puts "============ $fileName $fileDir"
set node [InsertTreeNode $fileName $fileDir]
#set node [NodeInsert $fileName $fileDir ""]
set activeFile $node
set replace 0 ;# for Overwrite procedure# execute external editor #
if {$editor(extern)=="Yes"} {
set pipe [open "|$editor(prog) $file" "r"]
fileevent $pipe readable
fconfigure $pipe -buffering none -blocking no
return
}
## check active file and if them don't exists return 0
if {[info exists files($node)] != 1} {
set files($node) [list $file 0]
set w [$nb insert end $node -text "$fileName"]
} else {
# puts "$file - already opened"
return
}
## update statusbar info
$status(fileAttr) configure -text "[FileAttr $file]"
$status(fileSize) configure -text "[file size $file] b."
$status(encode) configure -text "[lindex $files($node) 2]"
## create frames and text widget #
frame $w.f -borderwidth 2 -relief ridge
pack $w.f -side top -fill both -expand true
#supertext::text
supertext::text $w.f.text -yscrollcommand "$w.f.yscroll set" \
-relief sunken -wrap $editor(wrap) -highlightthickness 0 -font $font(editNormal)\
-background $color(editBg) -foreground $color(editFg)\
-selectborderwidth 0 -selectbackground $color(selectbg) -width 10
# lines numbering
#set txtLineNumber [text $w.f.text_lines -yscrollcommand "$w.f.yscroll set" \
#-relief sunken -wrap $editor(wrap) -highlightthickness 0 -font $font(editNormal)\
#-background $color(lineNumberBg) -foreground $color(lineNumberFg)\
#-selectborderwidth 0 -selectbackground $color(selectbg) -width 5]
scrollbar $w.f.yscroll -relief sunken -borderwidth {1} -width {10} -takefocus 0 \
-command "$w.f.text yview"
#pack $w.f.text_lines -side left -fill y
pack $w.f.text -side left -fill both -expand true
pack $w.f.yscroll -side left -fill y
$nb raise $node
## loadig tags for highlight procedure
LoadTag $w.f.text
#puts $w.f.text
## BACKUP FILE CREATED ##
if {$backup(create) == "Yes"} {
file copy -force -- $file [file join $dir(tmp) $fileName~]
}
## OPENED FILE ##
set fHandle [open "$file" r]
set sourceEnc [DocRecode $fHandle]
if {$sourceEnc == ""} {
set sourceEnc [encoding system]
}
lappend files($node) "$sourceEnc" ;# added encoding information
$status(encode) configure -text "[lindex $files($node) 2]"
set lineNumber 1
$treeStruct delete [$treeStruct nodes root] ;# delete all info about old structure
while {[gets $fHandle line]>=0} {
set line [encoding convertfrom $sourceEnc $line]
$w.f.text insert end "[string trimright $line]\n"
InsertStruct $node $line $lineNumber $fileDir
HighLightTEX $w.f.text $line $lineNumber $node
#$txtLineNumber insert end "$lineNumber\n"
incr lineNumber
}
close $fHandle
# key bindings #
set text $w.f.text
bind $text <Control-G> GoToLine
bind $text <Control-g> GoToLine
bind $text <Control-F> Find
bind $text <Control-f> Find
#bind $text <F2> SplitWindow
#bind $text <F6> {ConvertDialog ps}
#bind $text <F7> {ConvertDialog pdf}
bind $text <Control-R> ReplaceDialog
bind $text <Control-r> ReplaceDialog
#bind $text <F4> {ReplaceCommand $w.frame.text 1}
bind $text <Control-S> {FileDialog save}
bind $text <Control-s> {FileDialog save}
bind $text <Control-A> {FileDialog save_as}
bind $text <Control-a> {FileDialog save_as}
bind $text <Control-W> {FileDialog close}
bind $text <Control-w> {FileDialog close}
bind $text <Control-X> "tk_textCut $w.f.text;break"
bind $text <Control-x> "tk_textCut $w.f.text;break"
bind $text <Control-C> "tk_textCopy $w.f.text;break"
bind $text <Control-c> "tk_textCopy $w.f.text;break"
bind $text <Control-V> "tk_textPaste $w.f.text;break"
bind $text <Control-v> "tk_textPaste $w.f.text;break"
bind $text <Control-q> exit
bind $text <Control-Q> exit
bind $text <Control-z> "$text undo"
bind $text <Control-Z> "$text undo"
bind $text <Alt-c> AutoComplit
bind $text <Alt-C> AutoComplit
bind $text <Alt-f> "GenerateFormula math"
bind $text <Alt-F> "GenerateFormula math"
bind $text <Alt-t> "GenerateFormula text"
bind $text <Alt-T> "GenerateFormula text"
bind $text <ButtonRelease-1> {$status(pos) configure -text [%W index insert]}
bind $text <Insert> {OverWrite}
bind $text <Button-3> {catch [PopupMenu %W %X %Y]}
bind $text <KeyRelease-Return> {
AddText item
set pos [%W index insert]
set line [lindex [split $pos "."] 0]
set editLine [%W get $line.0 $pos]
HighLightTEX %W $editLine $line [$nb raise]
set node [$nb raise]
if {$node == "" || $node == "debug" || $node == "settings" || $node == "about"} {return 1}
if {[lindex $files($node) 1] == 0} {
set files($node) [list [lindex $files($node) 0] 1 [lindex $files($node) 2]]
$status(active) configure -text [::msgcat::mc "File modify"]
$nb itemconfigure $node -foreground $color(editTitleModify)
}
}
bind $text <KeyRelease> {
set node [$nb raise]
if {$node == "" || $node == "debug" || $node == "settings" || $node == "about"} {return 1}
set text "$nb.f$node.f.text"
set pos [$text index insert]
set line [lindex [split $pos "."] 0]
set symbol [lindex [split $pos "."] 1]
set editLine [$text get $line.0 $pos]
HighLightTEX $text $editLine $line $node
$status(pos) configure -text [$text index insert];# cursor position
if {$symbol >= $editor(strLen)} {
if {[Key %k] == "true"} {
if {$editor(strWrap) == "Yes"} {
#$text insert $line.end "\n"
set p [$text search -backward -regexp -- {\s} $pos $line.0]
if {$p !=""} {
$text insert "$p + 1 chars" "\n"
}
}
}
}
if {[Key %k] == "true"} {
if {[lindex $files($node) 1] == 0} {
set files($node) [list [lindex $files($node) 0] 1 [lindex $files($node) 2]]
$status(active) configure -text [::msgcat::mc "File modify"]
$nb itemconfigure $node -foreground $color(editTitleModify)
}
}
}
bind $text <KeyPress> {
if {[Key %k] == "true"} {
ReplaceChar %W
}
set node [$nb raise]
if {$node == "" || $node == "debug" || $node == "settings" || $node == "about"} {return 1}
set text "$nb.f$node.f.text"
set pos [$text index insert]
set line [lindex [split $pos "."] 0]
set symbol [lindex [split $pos "."] 1]
set editLine [$text get $line.0 $pos]
HighLightTEX $text $editLine $line $node
$status(pos) configure -text [$text index insert];# cursor position
if {$symbol >= $editor(strLen)} {
if {[Key %k] == "true"} {
if {$editor(strWrap) == "Yes"} {
#$text insert $line.end "\n"
set p [$text search -backward -regexp -- {\s} $pos $line.0]
if {$p !=""} {
$text insert "$p + 1 chars" "\n"
}
}
}
}
}
bind $text <KeyPress-space> {
if {[Key %k] == "true"} {
ReplaceChar %W
}
}
bind $text <KeyRelease-space> {
set node [$nb raise]
if {$node == "" || $node == "debug" || $node == "settings" || $node == "about"} {return 1}
if {[lindex $files($node) 1] == 0} {
set files($node) [list [lindex $files($node) 0] 1 [lindex $files($node) 2]]
$status(active) configure -text [::msgcat::mc "File modify"]
$nb itemconfigure $node -foreground $color(editTitleModify)
}
}
bind $text <Control-u> {
set i -1
switch -- [%W get "insert - 1 chars"] {
\{ {set i [_searchCloseBracket %W \{ \} insert end]}
\[ {set i [_searchCloseBracket %W \[ \] insert end]}
( {set i [_searchCloseBracket %W ( ) insert end]}
\} {set i [_searchOpenBracket %W \{ \} insert 1.0]}
\] {set i [_searchOpenBracket %W \[ \] insert 1.0]}
) {set i [_searchOpenBracket %W ( ) insert 1.0]}
} ;# switch
if { $i != -1 } {
%W mark set insert $i
%W see insert
}
} ;# bind
bindtags $text [list [winfo toplevel $text] $text Text sysAfter all]
bind sysAfter <Any-Key> {+ set i -1
catch {
switch -- [%W get "insert - 1 chars"] {
\{ {set i [_searchCloseBracket %W \{ \} insert end]}
\[ {set i [_searchCloseBracket %W \[ \] insert end]}
( {set i [_searchCloseBracket %W ( ) insert end]}
\} {set i [_searchOpenBracket %W \{ \} insert 1.0]}
\] {set i [_searchOpenBracket %W \[ \] insert 1.0]}
) {set i [_searchOpenBracket %W ( ) insert 1.0]}
} ;# switch
catch { %W tag remove lightBracket 1.0 end }
if { $i != -1 } {%W tag add lightBracket "$i - 1 chars" $i}
}
} ;# bind sysAfter
bind sysAfter <Button-1> [bind sysAfter <Any-Key>]
focus -force $w.f.text
Timer $file "refresh"
if {$backup(autosave) == "Yes"} {
Timer $file "autosave"
}
};# proc EditFile
proc _searchCloseBracket { widget o_bracket c_bracket start_pos end_pos } {
set o_count 1
set c_count 0
set found 0
set pattern "\[\\$o_bracket\\$c_bracket\]"
set pos [$widget search -regexp -- $pattern $start_pos $end_pos]
while { ! [string equal $pos {}] } {
set char [$widget get $pos]
#tk_messageBox -title $pattern -message "char: $char; $pos; o_count=$o_count; c_count=$c_count"
if {[string equal $char $o_bracket]} {incr o_count ; set found 1}
if {[string equal $char $c_bracket]} {incr c_count ; set found 1}
if {($found == 1) && ($o_count == $c_count) } { return [$widget index "$pos + 1 chars"] }
set found 0
set start_pos "$pos + 1 chars"
set pos [$widget search -regexp -- $pattern $start_pos $end_pos]
} ;# while search
return -1
} ;# proc _searchCloseBracket
# DEDERER
## Search open bracket in editor widget
proc _searchOpenBracket { widget o_bracket c_bracket start_pos end_pos } {
set o_count 0
set c_count 1
set found 0
set pattern "\[\\$o_bracket\\$c_bracket\]"
set pos [$widget search -backward -regexp -- $pattern "$start_pos - 1 chars" $end_pos]
while { ! [string equal $pos {}] } {
set char [$widget get $pos]
#tk_messageBox -title $pattern -message "char: $char; $pos; o_count=$o_count; c_count=$c_count"
if {[string equal $char $o_bracket]} {incr o_count ; set found 1}
if {[string equal $char $c_bracket]} {incr c_count ; set found 1}
if {($found == 1) && ($o_count == $c_count) } { return [$widget index "$pos + 1 chars"] }
set found 0
set start_pos "$pos - 0 chars"
set pos [$widget search -backward -regexp -- $pattern $start_pos $end_pos]
} ;# while search
return -1
} ;# proc _searchOpenBracket
proc GoToLine {} {
global nb files font color
set node [$nb raise]
if {$node == "newproj" || $node == "settings" || $node == "about" || $node == ""} {
return
}
set file $files($node)
set w $nb.f$node.goto
set text "$nb.f$node.f.text"
# destroy the find window if it already exists
if {[winfo exists $w]} {
destroy $w
}
# create the new "goto" window
toplevel $w
wm title $w [::msgcat::mc "Goto line"]
wm resizable $w 0 0
wm transient $w $nb.f$node
label $w.text -text [::msgcat::mc "Line number"] -font $font(normal) -background $color(bg)
entry $w.entGoTo -width 6 -validate key -validatecommand "ValidNumber %W %P"
pack $w.text $w.entGoTo -side left -anchor nw -padx 2 -pady 2
set line [$w.entGoTo get]
bind $w.entGoTo <Return> "+GoToLineNumber $text $nb.f$node"
bind $w.entGoTo <Escape> "destroy $w"
focus -force $w.entGoTo
}
## Check input number ##
proc ValidNumber {w value} {
if [string is integer $value] {
return 1
} else {
bell
return 0
}
}
## GOTO LINE ##
proc GoToLineNumber {text w} {
global status
set lineNumber [$w.goto.entGoTo get]
destroy $w.goto
catch {
$text mark set insert $lineNumber.0
$text see insert
}
$status(pos) configure -text [$text index insert];# cursor position
}
## SEARCH DIALOG FORM ##
set findHistory ""
set findString ""
set replaceString ""
proc Find {} {
global nb files font findHistory findString color
set node [$nb raise]
if {$node == "newproj" || $node == "settings" || $node == "about" || $node == ""} {
return
}
set file $files($node)
set w $nb.f$node.find
set text "$nb.f$node.f.text"
set findString ""
# destroy the find window if it already exists
if {[winfo exists $w]} {
destroy $w
}
toplevel $w
wm title $w [::msgcat::mc "Find"]
wm resizable $w 0 0
wm transient $w $nb.f$node
frame $w.frmCombo -borderwidth 1 -background $color(bg)
frame $w.frmBtn -borderwidth 1 -background $color(bg)
pack $w.frmCombo $w.frmBtn -side top -fill x
# set combo [entry $w.frmCombo.entFind]
set combo [ComboBox $w.frmCombo.txtLocale\
-textvariable findString -background $color(bg)\
-selectbackground "#55c4d1" -selectborderwidth 0\
-values $findHistory]
pack $combo -fill x -padx 2 -pady 2
button $w.frmBtn.btnFind -text "[::msgcat::mc "Find"] - F3"\
-font $font(normal) -width 12 -relief groove -background $color(bg)\
-command "FindCommand $text $w"
button $w.frmBtn.btnCancel -text "[::msgcat::mc "Close"] - Esc"\
-relief groove -width 12 -font $font(normal) -background $color(bg)\
-command "destroy $w"
pack $w.frmBtn.btnFind $w.frmBtn.btnCancel -fill x -padx 2 -pady 2 -side left
bind $w <Return> "FindCommand $text $w"
bind $w <F3> "FindCommand $text $w"
bind $w <Escape> "destroy $w"
focus -force $combo
# set findIndex [lsearch -exact $findHistory "$findString"]
$combo setvalue @0
}
proc FindCommand {text w} {
global findString findHistory
# set findString [$entry get]
destroy $w
# if null string? do nothing
if {$findString == ""} {
return
}
# search "again" (starting from current position)
FindNext $text 0
}
proc FindNext {text {incr 1}} {
global findString findHistory
set t $text
# append find string into find history list #
if {[lsearch -exact $findHistory $findString] == -1} {
set findHistory [linsert $findHistory 0 $findString]
}
set pos [$t index insert]
set line [lindex [split $pos "."] 0]
set x [lindex [split $pos "."] 1]
incr x $incr
set pos [$t search -nocase $findString $line.$x end]
# if found then move the insert cursor to that position, otherwise beep
if {$pos != ""} {
$t mark set insert $pos
$t see $pos
# highlight the found word
set line [lindex [split $pos "."] 0]
set x [lindex [split $pos "."] 1]
set x [expr {$x + [string length $findString]}]
$t tag remove sel 1.0 end
$t tag add sel $pos $line.$x
focus -force $t
return 1
} else {
bell
return 0
}
catch [$status(pos) configure -text [%W index insert]] ;# cursor position
}
## FIND FUNCTION PROCEDURE ##
proc FindProc {text findString node} {
global nb status
set pos "0.0"
$text see $pos
set line [lindex [split $pos "."] 0]
set x [lindex [split $pos "."] 1]
set pos [$text search -nocase $findString $line.$x end]
$text mark set insert $pos
$text see $pos
# highlight the found word
set line [lindex [split $pos "."] 0]
set x [lindex [split $pos "."] 1]
set x [expr {$x + [string length $findString]}]
$text tag remove sel 1.0 end
$text tag add sel $pos $line.$x
focus -force $text
catch [$status(pos) configure -text [$text index insert]] ;# cursor position
return 1
}
#3 REPLACE DIALOG FORM ##
proc ReplaceDialog {} {
global nb font files findString replaceString text color
set node [$nb raise]
if {$node == "newproj" || $node == "settings" || $node == "about" || $node == ""} {
return
}
#set file $files($node)
set w .replace
set text "$nb.f$node.f.text"
# set findString ""
# destroy the find window if it already exists
if {[winfo exists $w]} {
destroy $w
}
# create the new "find" window
toplevel $w
wm transient $w $nb.f$node
wm title $w [::msgcat::mc "Replace"]
wm resizable $w 0 0
set f1 [frame $w.frmFind -background $color(bg)]
set f2 [frame $w.frmReplace -background $color(bg)]
set f3 [frame $w.frmBtn -borderwidth 1 -background $color(bg)]
pack $f1 $f2 $f3 -side top -fill x -expand true
label $f1.lblFind -text [::msgcat::mc "Find"] -font $font(normal) -width 15 -anchor w -background $color(bg)
entry $f1.entFind -width 30
pack $f1.lblFind $f1.entFind -side left -padx 2 -pady 2
pack $f1.entFind -side left -fill x -expand true -padx 2 -pady 2
label $f2.lblReplace -text [::msgcat::mc "Replace with"] -font $font(normal) -width 15 -anchor w -background $color(bg)
entry $f2.entReplace -width 30
pack $f2.lblReplace $f2.entReplace -side left -padx 2 -pady 2
pack $f2.entReplace -side left -fill x -expand true -padx 2 -pady 2
button $f3.btnFind -text "[::msgcat::mc "Find"] - Enter" -width 12 -pady 0 -font $font(normal) -relief groove -background $color(bg)\
-command "ReplaceCommand $text $w $f1.entFind $f2.entReplace find"
button $f3.btnReplace -text "[::msgcat::mc "Replace"] - F4" -width 12 -pady 0\
-font $font(normal) -relief groove -background $color(bg)\
-command {
ReplaceCommand $text $w .replace.frmFind.entFind .replace.frmReplace.entReplace replace
focus -force .replace
}
button $f3.btnReplaceAll -text [::msgcat::mc "Replace all"] -width 12 -pady 0\
-font $font(normal) -relief groove -background $color(bg)\
-command "ReplaceCommand $text $w $f1.entFind $f2.entReplace replace_all"
button $f3.btnCancel -text "[::msgcat::mc "Cancel"] - Esc" -command "destroy $w"\
-width 12 -pady 0 -font $font(normal) -relief groove -background $color(bg)
pack $f3.btnFind $f3.btnReplace $f3.btnReplaceAll $f3.btnCancel\
-side left -padx 2 -pady 2 -fill x
bind $w <Return> "ReplaceCommand $text $w $f1.entFind $f2.entReplace find"
bind $w <F4> "ReplaceCommand $text $w $f1.entFind $f2.entReplace replace"
bind $w <Escape> "destroy $w"
focus -force $f1.entFind
if {$findString != ""} {
$f1.entFind insert end $findString
}
if {$replaceString != ""} {
$f2.entReplace insert end $replaceString
}
}
## REPLACE COMMAND ##
proc ReplaceCommand {text w entFind entReplace command} {
global nb font files findString replaceString
set node [$nb raise]
set findString [$entFind get]
set replaceString [$entReplace get]
switch -- $command {
"find" {
FindNext $text 1
focus -force .replace
}
"replace" {
if {[Replace $text 0]} {
FindNext $text 1
if {[lindex $files($node) 1] == 0} {
set files($node) [list [lindex $files($node) 0] 1 [lindex $files($node) 2]]
}
focus -force .replace
}
}
"replace_all" {
set stringsReplace 0
if {[Replace $text 0]} {
if {[lindex $files($node) 1] == 0} {
set files($node) [list [lindex $files($node) 0] 1 [lindex $files($node) 2]]
}
incr stringsReplace
while {[Replace $text 1]} {
incr stringsReplace
}
}
tk_messageBox -icon info -title [::msgcat::mc "Replace"]\
-parent $text -message\
"[::msgcat::mc "Was replacement"] $stringsReplace."
destroy $w
}
}
}
## REPLACE ONE WORD PROCEDURE ##
proc Replace {text incr} {
global nb font files findString replaceString
if {[FindNext $text $incr]} {
set selected [$text tag ranges sel]
set start [lindex $selected 0]
set end [lindex $selected 1]
$text delete $start $end
$text insert [$text index insert] $replaceString
return 1
} else {
return 0
}
# focus -force .replace
}
## OVERWRITE SYMBOL PROCEDURE ##
proc OverWrite {} {
global replace fontNormal status
if {$replace == 1} {
set replace 0
$status(ovwrt) configure -text [::msgcat::mc "Insert"] -foreground black
} else {
set replace 1
$status(ovwrt) configure -text [::msgcat::mc "Overwrite"] -foreground red
}
}
proc ReplaceChar {text} {
global replace
set pos [$text index insert]
set posY [lindex [split $pos "."] 0]
set posX [lindex [split $pos "."] 1]
if {$replace == 1} {
$text delete $posY.$posX $posY.[expr $posX + 1]
}
}
## GET KEYS CODE ##
proc Key {key} {
#puts $key ;#debug
if {$key >= 10 && $key <= 22} {return "true"}
if {$key >= 24 && $key <= 36} {return "true"}
if {$key >= 38 && $key <= 50} {return "true"}
if {$key >= 51 && $key <= 61 && $key != 58} {return "true"}
if {$key >= 79 && $key <= 91} {return "true"}
if {$key == 63 || $key == 107 || $key == 108 || $key == 112} {return "true"}
if {$key == 98 || $key == 100 || $key == 102 || $key == 104} {return "false"}
}
## SPLIT EDITOR WINDOW PROCEDURE ##
set split 0
proc SplitWindow {} {
global color font editor nb activeFile split
if [info exists activeFile] {
set w $nb.f$activeFile
} else {
return
}
if {$split == 0} {
frame $w.f1 -borderwidth 2 -relief ridge
pack $w.f1 -side top -fill both -expand true
#supertext::text
supertext::text $w.f1.text -yscrollcommand "$w.f1.yscroll set" \
-relief sunken -wrap $editor(wrap) -highlightthickness 0 -font $font(editNormal)\
-background $color(editBg) -foreground $color(editFg)\
-selectborderwidth 0 -selectbackground $color(selectbg) -width 10
scrollbar $w.f1.yscroll -relief sunken -borderwidth {1} -width {10} -takefocus 0 \
-command "$w.f1.text yview"
pack $w.f1.text -side left -fill both -expand true
pack $w.f1.yscroll -side left -fill y
##############################################
pane::create $w.f $w.f1 -orient horizontal -percent 0.5
set split 1
} elseif {$split == 1} {
destroy $w.f1
}
}