########################################################################
#
# "latex_tcl" : Tvi, LaTeX のためのプロシージャ群
#
# Copyright (c) 1998,1999  Motomu Nakashima
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option) 
# any later version.
#
# This program is distributed in the hope that it will be useful, 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
# GNU General Public License for more details.
#
########################################################################

# コンパイル
proc compiling { } {
    global filename
    global dvifilename
    global tvi_directory filename short_filename 
    global saved_flag 
    global terminal_command
    global latex_command
    global latex_offset_x
    global latex_offset_y
    global latex_title
    global x_pointer
    global y_pointer
    global aux_time

    # まずエスケープ
    set focus_now [ focus ]
    if {$focus_now == ".text"} {
        for_redo_end
        .text tag remove inserted_text_tag 1.0 end
        escaping
        clear_mem_y
        catch {kanjiInput end .text}
        for_unundo i
    }

    # 次に保存
    set f [ open $filename w ]
    puts -nonewline $f [.text get 1.0 end ]
    close $f
    set saved_flag 1

    .navi.main configure -state normal
    .navi.main delete 0 end 
    .navi.main insert insert "`$short_filename'" 
    .navi.main insert insert { [}
    set linenumber [.text index "end -1 c linestart"]
    set linenumber [expr int($linenumber)]
    .navi.main insert insert  $linenumber

    if { $linenumber == 1 } {
        .navi.main insert insert { line]}
    } else {
        .navi.main insert insert { lines]}
    }
    .navi.main configure -state disabled

    update ; # 保存終了

    set x_pointer [winfo x .]
    set y_pointer [winfo y .]
    set latex_title {"Compiling..."}
    eval { exec $terminal_command -title $latex_title -geometry \
 +[expr $x_pointer $latex_offset_x]+[expr $y_pointer $latex_offset_y ] \
                    -e $latex_command $dvifilename & }

    # エラー時の処理
    #set logfilename [string trimright $filename tex]
    #set logfilename [string trimright $logfilename "." ]
    #set error [catch { set error_msg [ exec grep ^l\. $logfilename.log ]}]
    #if { $error != 0 } { return } ;# 空ならすぐ抜ける
    #set error_msg [string trimleft $error_msg l. ]
    #set error_msg [lindex $error_msg 0]
    #.text mark set insert $error_msg.0
    #cursor_put
    #.text tag add latex_error "insert linestart" "insert lineend"
    #update
    #belll
    #after 3000 { .text tag remove latex_error 1.0 end }
}

# xdvi の起動
proc xdvi_start { } {
    global filename
    global dvifilename
    global xdvi_command
    global xdvi_option
    global xdvi_paper
    #set dvifilename [string trimright $filename tex]
    #set dvifilename [string trimright $dvifilename "." ]

    eval exec $xdvi_command \
                   -paper $xdvi_paper $xdvi_option $dvifilename &
}

# LaTeX モードへの移行
proc into_latex_mode { } { 
pack forget .latex 
pack .latex -side bottom
}

# Normal モードへの移行
proc into_normal_mode { } { 
pack forget .latex 
}

# 数式パネルの起動／終了
proc equation_panel_onoff { } { 
     global equation_panel_flag
     if {$equation_panel_flag == 0 } {
        wm deiconify .panel
     set equation_panel_flag 1
     } elseif {$equation_panel_flag == 1 } {
        wm withdraw .panel
        set equation_panel_flag 0
     }
}

#######################################################################
#
#   LaTeXソースを見やすくするための色付け部(Emacsを参考)
#
#######################################################################

# 色づけの解除
proc uncolorize { } {
    global fore_color
    global back_color
    .text tag remove figure    1.0 end
    .text tag remove equation  1.0 end
    .text tag remove section   1.0 end
    .text tag remove bad_spell 1.0 end
    .text tag remove comment   1.0 end
    .text tag remove decl      1.0 end
    #.text tag remove formula   1.0 end
    .text tag configure formula -foreground $fore_color \
                                -background $back_color
    #.text tag lower formula section
    .text tag raise formula label
    .text tag remove label     1.0 end
    .text tag remove keyword   1.0 end
    .text tag remove special   1.0 end
    .text tag remove include   1.0 end
    .text tag remove crossref  1.0 end
    .text tag remove define    1.0 end
    .text tag remove defun     1.0 end
}

# 色づけプロシージャ(searchコマンド利用バージョン)
proc colorize { s e } {
    global s_start s_end
    global back_color
    global formula_conf
    #set s_start $s
    #set s_end   $e
    set s_start [.text index "$s linestart"]
    set s_end   [.text index "$e lineend"]

    if {$e=="end"} {
        .text configure -cursor watch
        update
    }

    # コメント

    # コメントの場合，外れることがあるので一旦消去する
    .text tag remove comment "$s_start linestart" "$s_end lineend"

    set search_end 0
    #.text mark set search_tag 1.0
    .text mark set search_tag "$s_start linestart"
    while { $search_end == 0 } {
        set start_index \
              [.text search -forward % search_tag "$s_end lineend"]
        if {$start_index ==""} { 
            set search_end 1 ;# 無かったら終わり
        } else {
            # 直前がバックスラッシュじゃないときだけタグ付けして次行へ
            if {[.text get "$start_index -1c"]!="\\"} {
                .text tag add comment \
                       $start_index "$start_index lineend +1c"
                .text mark set search_tag "$start_index lineend +1c"
                # 最後の行だったら終わり
                if {[.text index "$start_index lineend +1c"] \
                        ==[.text index end]} { set search_end 1 }
            } else {
                .text mark set search_tag "$start_index +1c"
            }
        }
    }
    if {$e=="end"} {update}

    # setlength など
    color_command {\\((setlength)|(settowidth)|(addtolength)|(setcounter)|(addtocounter))\{[^{}]*\}} {(^|[^\\])\{} {(^|[^\\])\}} define
    if {$e=="end"} {update}

    # documentstyle など
    color_command {\\documentstyle(\[.*\])?} {(^|[^\\])\{} {(^|[^\\])\}} decl

    # pagestyle など
    color_command {\\((pagestyle)|(thispagestyle)|(pagenumbering))} {(^|[^\\])\{} {(^|[^\\])\}} decl
    color_command {\\includeonly} {(^|[^\\])\[} {[^\\]\]} decl
    if {$e=="end"} {update}

    # 短い begin, end
    color_command {(\\begin)|(\\end)} {(^|[^\\])\{} {[^\\]\}} decl
    #color_only_the_command2 {((\\begin)|(\\end))\{.+\}} decl
    # 長い begin
    color_command {\\begin{[^{}]*}} {(^|[^\\])\{} {[^\\]\}} decl
    #color_only_the_command2 {\\begin\{.+\}\{.+\}} decl

    # vspace, hspace
    color_command {\\(v|h)space\*?} {(^|[^\\])\{} {((^)|([^\\]))\}} keyword
    #color_only_the_command2 {\\(v|h)space\*?\{.+\}} keyword

    # renewcommand, renewenvironments など
    color_command {\\(re)?new((command)|(environment))\{[^{}]*\}(\[.+\])?} {(^|[^\\])\{} {(^|[^\\])\}} defun
    color_command {\\newtheorem\{[^{}]*\}(\[.+\])?} {(^|[^\\])\{} {(^|[^\\])\}} defun
    color_command {\\new((length)|(counter))} {(^|[^\\])\{} {(^|[^\\])\}} defun
    if {$e=="end"} {update}

    # item (オプションなし)
    color_only_the_command {\\item} label
    # item (オプションあり)
    color_command {\\item} {(^|[^\\])\[} {((^)|([^\\]))\]} label
    if {$e=="end"} {update}

    # 数式
    eval .text tag configure formula  "$formula_conf"
    #.text tag lower formula section
    .text tag raise formula label
    colorize_formula $s_start $s_end
    if {$e=="end"} {update}

    # 〜box コマンド(引数なし)
    color_only_the_command {\\[a-z]+box} keyword

    # 〜box コマンド(引数，オプションあり)
    color_command {\\[a-z]+box(\[.+\])?} {(^|[^\\])\{} {((^)|([^\\]))\}} keyword
    # footnote, footnotemark, footnotetext
    color_command {\\footnote((mark)|(text))?(\[.+\])?} {(^|[^\\])\{} {((^)|([^\\]))\}} keyword

    # chapter,section,paragraph など
    color_command {(\\part\*?)|(\\chapter\*?)|(\\(sub)*((section)|(paragraph))\*?)} {(^|[^\\])\{} {((^)|([^\\]))\}} section

    if {$e=="end"} {update}

    # title など
    color_command {\\((title)|(author)|(date)|(thanks))} {(^|[^\\])\{} {(^|[^\\])\}} define
    if {$e=="end"} {update}

    # maketitle など
    set regexp_arg {((\\raggedright)|(\\makeindex)|(\\makeglossary)|(\\maketitle)|(\\nofiles))}
    color_only_the_command ${regexp_arg} decl 
    set regexp_arg {(\\newline)|(\\((big)|(med)|(small))skip)|(\\clearpage)}
    color_only_the_command ${regexp_arg} decl 

    color_command {\\twocolumn} {(^|[^\\])\[} {((^)|([^\\]))\]} decl

    set regexp_arg {(\\appendix)|(\\tableofcontents)|(\\listoffigures)|(\\listoftables)}
    color_only_the_command ${regexp_arg} decl 
    if {$e=="end"} {update}
    # bf など
    set regexp_arg {(\\bf)|(\\em)|(\\it)|(\\rm)}
    color_only_the_command ${regexp_arg} decl 
    set regexp_arg {(\\sf)|(\\sl)|(\\ss)|(\\tt)}
    color_only_the_command ${regexp_arg} decl 
    set regexp_arg {(\\normalsize)|(\\small)|(\\footnotesize)|(\\scriptsize)|(\\tiny)}
    color_only_the_command ${regexp_arg} decl 
    set regexp_arg {(\\large)|(\\Large)|(\\LARGE)|(\\huge)|(\\Huge)}
    color_only_the_command ${regexp_arg} decl 
    if {$e=="end"} {update}
    # caption
    color_command {\\caption(\[.*\])?} {(^|[^\\])\{} {((^)|([^\\]))\}} label

    # special
    color_command {\\special} {(^|[^\\])\{} {((^)|([^\\]))\}} special

    # include など
    color_command {((\\include)|(\\input)|(\\bibliography))} {(^|[^\\])\{} {((^)|([^\\]))\}} include

    # crossref 関係
    color_command {(\\(no)?cite)|(\\(page)?ref)|(\\label)|(\\index)|(\\glossary)|(\\bibitem)} {(^|[^\\])\{} {((^)|([^\\]))\}} crossref
    if {$e=="end"} {update}    

    # LaTeX2ε固有コマンド
    #
    set regexp_arg {(\\color)|(\\textcolor)|(\\(rotate|scale|resize)box\{[^\{\}]*\})}
    color_only_the_command ${regexp_arg} decl 

    # documentclass
    color_command {\\documentclass(\[.*\])?} {(^|[^\\])\{} {(^|[^\\])\}} decl

    # includegraphics
    color_command {\\includegraphics(\*[^\{\}]*)?} {(^|[^\\])\{} {((^)|([^\\]))\}} special

    # bfseries など
    set regexp_arg {(\\(rm|sf|tt|mc|gt)family)|(\\(md|bf)series)|(\\(up|it|sl|sc)shape)|(\\normalfont)}
    color_only_the_command ${regexp_arg} decl 

    # textrm など
    color_command {\\text(rm|sf|tt|mc|gt|md|bf|up|it|sl|sc|normal)} {(^|[^\\])\{} {((^)|([^\\]))\}} decl

    # 後処理
    if {$e=="end"} {
        .text configure -cursor xterm
    }
        update
}

# 色付け
proc color_command { command open close tag } {
    global s_start s_end
    set search_end 0
    .text mark set search_tag $s_start
    while { $search_end == 0 } {
        set start_index [.text search -forward -count word_len \
                            -regexp ${command} search_tag $s_end ]
        if {$start_index ==""} { 
            set search_end 1 ;# 無かったら終わり
        } else {
            # word_len の分だけカーソルを進めておく
            .text mark set search_tag "$start_index +$word_len c"

            # さらに後ろに { } がある場合に以下の処理をおこなう
            if {[regexp ${open} \
                [.text get "search_tag -1c" "search_tag +1c"]] == 1 } {

            # 以下は後ろの閉じ括弧を見つけるため
            .text mark set open_index_start search_tag
            .text mark set close_index_start search_tag

            set stop 0
            while {$stop == 0} { 
                set tmp [.text search -forward -count word_len \
                          -regexp ${close} close_index_start $s_end]
                if {$tmp == ""} { return }
                .text mark set close_index $tmp
                set results [.text search -forward \
                          -regexp ${open} open_index_start close_index ]
                if {$results == ""} { 
                    set stop 1 ;# 抜けてタグ付けへ
                } else {
                    .text mark set close_index_start  "close_index +1c"
                    .text mark set open_index_start "$results +1c"
                }       
            }
            .text tag add $tag $start_index "close_index +$word_len c"
            .text mark set search_tag "close_index +1c"
            }
        }
    }
}


# そのコマンドだけ色づけすれば良いものに色付けする(次の文字も判断)
proc color_only_the_command { regexp_arg tag } {
    global s_start s_end
    set search_end 0
    .text mark set search_tag $s_start
    while { $search_end == 0 } {
        set start_index [.text search -forward -count word_len \
                            -regexp ${regexp_arg} search_tag $s_end ]
        if {$start_index ==""} { 
            set search_end 1 ;# 無かったら終わり
        } else {
            # コマンドの次の文字が[a-zA-Z]じゃなければタグ付け
            if {[regexp {[a-zA-Z]} \
                    [.text get "$start_index +$word_len c"]]==0 } {
               .text tag add $tag \
                    $start_index "$start_index +$word_len c"
            }
            .text mark set search_tag "$start_index +1c"
        }
    }
}

# そのコマンドだけ色づけすれば良いものに色付けする(次の文字も判断)
proc color_only_the_command2 { regexp_arg tag } {
    global s_start s_end
    set search_end 0
    .text mark set search_tag $s_start
    while { $search_end == 0 } {
        set start_index [.text search -forward -count word_len \
                            -regexp ${regexp_arg} search_tag $s_end ]
        if {$start_index ==""} { 
            set search_end 1 ;# 無かったら終わり
        } else {
               .text tag add $tag \
                    $start_index "$start_index +$word_len c"
            .text mark set search_tag "$start_index +1c"
        }
    }
}


# 数式の色付け
proc colorize_formula { s_start s_end } {
    #global s_start s_end

    # 文中数式
    set search_end 0
    set begin_or_end 0
    .text mark set search_tag $s_start
    while { $search_end == 0 } {
     if {$begin_or_end == 0} {
         set start_index [.text search -forward \
                     -regexp {((\$)|(\\\()|(\\\[))} search_tag $s_end ]
         if {$start_index ==""} { 
            set search_end 1 
         } else {
            .text mark set search_tag $start_index+1c
            # 前がバックスラッシュでないときだけ良しとする
            if {[.text get "$start_index -1c"]!="\\"} {
               set begin_or_end 1  
            }
         }
     } else {
         set end_index [.text search -forward -count word_len \
             -regexp {((\$)|(\\\))|(\\\]))} search_tag $s_end ]
         if {$end_index ==""} { 
            #belll
            set search_end 1 
         } else {
            .text mark set search_tag $end_index+1c
            # 前がバックスラッシュでないときだけ良しとする
            if {[.text get "$start_index -1c"]!="\\"} {
               set begin_or_end 0  
               .text tag add formula $start_index \
                                     "$end_index+$word_len c"
            }
         }
     }
    }

    # 数式
    set search_end 0
    set begin_or_end 0
    .text mark set search_tag "$s_start linestart -1c linestart"
    while { $search_end == 0 } {
     if {$begin_or_end == 0} {
         set start_index [.text search -forward -count word_len \
          -regexp {(\\begin\{math\})|(\\begin\{displaymath\})|(\\begin\{equation\})|(\\begin\{eqnarray\})|(\\begin\{eqnarray\*\})} search_tag $s_end]
         if {$start_index ==""} { 
            set search_end 1 
         } else {
            set start_index [.text index "$start_index + $word_len c"]
            .text mark set search_tag $start_index+1c
            set begin_or_end 1  
         }
     } else {
         set end_index [.text search -forward -count word_len \
          -regexp {(\\end\{math\})|(\\end\{displaymath\})|(\\end\{equation\})|(\\end\{eqnarray\})|(\\end\{eqnarray\*\})} search_tag "$s_end lineend +1c lineend"]
         if {$end_index ==""} { 
            #belll
            set search_end 1 
         } else {
            .text mark set search_tag $end_index+1c
            set begin_or_end 0  
            .text tag add formula $start_index "$end_index"
         }
     }
    }
}

########################################################################
#     LaTeX の文法チェック関係
########################################################################

# 入力した文字が LaTeX のコマンド・環境リストに載っているかどうか
# をチェックする
proc latex_check { } {
    global latex_cmds latex_envs latex_symbols
    global isi iei
    global latex_check_on

    if {$latex_check_on==0} { return }

    # バックスラッシュで始まるコマンド名をチェックする
    set search_end 0
    #.text mark set search_tag "$isi linestart"
    .text mark set search_tag $isi
    while { $search_end == 0 } {
        set start_index [.text search -forward -count word_len \
            -regexp {\\[a-zA-Z]+} search_tag $iei]
            # -regexp {\\[a-zA-Z]+} search_tag "$iei lineend"]
        if {$start_index ==""} { 
            set search_end 1 ;# 無かったら終わり
        } else {
            set checkword \
              [.text get $start_index+1c "$start_index+$word_len c"]
            set results [lsearch -exact $latex_cmds $checkword]
            if {$results=="-1"} {
                .text tag add latex_error \
                       $start_index "$start_index+$word_len c"
                after 3000 { .text tag remove latex_error 1.0 end }
                belll
            }
            .text mark set search_tag $start_index+1c
        }
    }

    # begin, end の後の環境名をチェックする
    set search_end 0
    # .text mark set search_tag "$isi linestart"
    .text mark set search_tag $isi
    while { $search_end == 0 } {
        set start_index [.text search -forward -count word_len \
            -regexp {(\\begin\{)|(\\end\{)} search_tag $iei]
            # -regexp {(\\begin\{)|(\\end\{)} search_tag "$iei lineend"]
        if {$start_index ==""} { 
            set search_end 1 ;# 無かったら終わり
        } else {
            set end_index [.text search -forward -regexp {\}} \
                                       search_tag $iei]
                                       # [search_tag "$iei lineend"]
            set checkword \
                    [.text get "$start_index+$word_len c" $end_index]
            set results [lsearch -exact $latex_envs $checkword]
            if {$results=="-1"} {
                .text tag add latex_error \
                       "$start_index+$word_len c" $end_index
                after 3000 { .text tag remove latex_error 1.0 end }
                belll
            }
            .text mark set search_tag $end_index+1c
        }
    }

    # 数式の symbol の前にバックスラッシュがあるかをチェックする

    # formula タグがなければすぐ抜ける
    set taglist [.text tag names $isi]
    if {([.text tag nextrange formula $isi $iei]=="") && \
        ([lsearch -exact $taglist formula]=="-1")} { return }

    set search_end 0
    .text mark set search_tag "$isi linestart"
    while { $search_end == 0 } {
        set start_index [.text search -forward -count word_len \
            -regexp {[a-zA-Z]+} search_tag "$iei lineend"]
        if {$start_index ==""} { 
            set search_end 1 ;# 無かったら終わり
        } else {
            set checkword \
              [.text get $start_index "$start_index+$word_len c"]
            set results [lsearch -exact $latex_symbols $checkword]
            if {$results!="-1"} {
                set taglist [.text tag names $start_index+1c]
                if {([.text get $start_index-1c]!="\\") && \
                    ([lsearch -exact $taglist formula]!="-1")} { 
                    .text tag add latex_error \
                       $start_index "$start_index+$word_len c"
                    after 3000 { .text tag remove latex_error 1.0 end }
                    belll
                }
            }
            .text mark set search_tag "$start_index+$word_len c"
        }
    }
}

#######################################
#    Tab によるコマンド補完機能       # 
#######################################
proc tab_in_text { } {
    global latex_envs latex_cmds do_complement

    # 補完機能をオフにしてある場合，Tab を入れてすぐ抜ける
    if {$do_complement==0} {
        tkTextInsert .text \t
        after 10 focus .text
    }

    # まず後向きに search して insert に最も近い \ の位置を知る
    set bsi [.text search -backwards -exact \\ insert]
    # \ から insert までの文字を得る
    set word [.text get $bsi insert]

    # 環境かどうかの判断
    if {[regexp {\\(begin|end)\{[a-zA-Z]+$} $word]=="1"} {

        # word の前を切り取って環境名の部分だけにする
        set word [string trimleft $word "\\beginend"]
        set word [string trimleft $word "\{"]

        # word* が latex_envs の中の要素にマッチするか search
        set num_match 0
        set results 0
        set latex_envs2 $latex_envs
        while {$results!="-1"} {
            set results [lsearch -glob $latex_envs2 "${word}*"]
            if {$results=="-1"} { break } ;# マッチしなくなったら break
            # マッチした場合，そのコマンド名を得る
            incr num_match
            set comp_word($num_match) [lindex $latex_envs2 $results]
            # 複数ヒットするか調べるため，ヒットしたものを
            # どうでもいい文字に置き換える
            set latex_envs2 \
                     [lreplace $latex_envs2 $results $results aaaaa]
        }
        # 一つもマッチしなかった場合，ベルを鳴らして抜ける
        if {$num_match=="0"} { bell ; after 10 focus .text ; return }

        # 一つ以上マッチした場合，何文字目まで同じか見つける
        set char_end [string length $comp_word(1)]        
        set flag 0
        for {set char 0} {$char<$char_end} {incr char} {
            # まず１番目にマッチしたものの文字を得る
            set char1 [string index $comp_word(1) $char] 
            # n 番目が１番目と一致しているか
            for {set n 1} {$n<=$num_match} {incr n} {
                set charn [string index $comp_word($n) $char] 
                # 一致していなければフラグを立てる
                if {$char1!=$charn} { set flag 1 }
            }
            if {$flag==1} { break } ;# フラグが立っていれば break
        }
        # word の文字数分だけテキストを消去
        .text delete "insert- [string length $word] c" insert

        # (途中までの)文字を得る
        set comp_word2 [string range $comp_word(1) 0 [expr $char -1] ]
        # (途中までの)コマンド名を入力
        .text insert insert  $comp_word2

        if {$num_match!=1} { bell } ;# 二つ以上の場合ベルを鳴らす

        # 一つだけの場合，閉じ括弧も入れる
        if {$num_match==1} { 
            .text insert insert \}
        }

    # コマンドかどうかの判断
    } elseif {[regexp {\\[a-zA-Z]+$} $word]=="1"} {

        # word の前を切り取ってコマンド名の部分だけにする
        set word [string trimleft $word "\\"]

        # word* が latex_cmds の中の要素にマッチするか search
        set num_match 0
        set results 0
        set latex_cmds2 $latex_cmds
        while {$results!="-1"} {
            set results [lsearch -glob $latex_cmds2 "${word}*"]
            if {$results=="-1"} { break } ;# マッチしなくなったら break
            # マッチした場合，そのコマンド名を得る
            incr num_match
            set comp_word($num_match) [lindex $latex_cmds2 $results]
            # 複数ヒットするか調べるため，ヒットしたものを
            # どうでもいい文字に置き換える
            set latex_cmds2 \
                     [lreplace $latex_cmds2 $results $results aaaaa]
        }
        # 一つもマッチしなかった場合，ベルを鳴らして抜ける
        if {$num_match=="0"} { bell ; after 10 focus .text ; return }

        # 一つ以上マッチした場合，何文字目まで同じか見つける
        set char_end [string length $comp_word(1)]        
        set flag 0
        for {set char 0} {$char<$char_end} {incr char} {
            # まず１番目にマッチしたものの文字を得る
            set char1 [string index $comp_word(1) $char] 
            # n 番目が１番目と一致しているか
            for {set n 1} {$n<=$num_match} {incr n} {
                set charn [string index $comp_word($n) $char] 
                # 一致していなければフラグを立てる
                if {$char1!=$charn} { set flag 1 }
            }
            if {$flag==1} { break } ;# フラグが立っていれば break
        }
        # word の文字数分だけテキストを消去
        .text delete "insert- [string length $word] c" insert

        # (途中までの)文字を得る
        set comp_word2 [string range $comp_word(1) 0 [expr $char -1] ]
        # (途中までの)コマンド名を入力
        .text insert insert  $comp_word2

        if {$num_match!=1} { bell } ;# 二つ以上の場合ベルを鳴らす

        
    # 何も該当しなければただの Tab の入力とみなす
    } else {
        tkTextInsert .text \t
    }
    after 10 focus .text
}

########################
# コンパイルログの閲覧 #
########################
proc show_compile_log { } {
    global terminal_command
    global dvifilename
    global less_command
    exec $terminal_command -title "compile log" \
                    -e $less_command $dvifilename.log &
}

#######################################################
# プリントアウト関係
#######################################################
set dvi2ps_option_start 0
set dvi2ps_option_end   9999
set dvi2ps_option_paper  a4

# プリントウインドゥの起動
proc print_window { } {
    global ghostview_on
    global copy_number
    set ghostview_on 0 ; #ポップアップ時には ghostview は起動しない
    set copy_number 1 ; # 部数を１
    set x [expr [winfo rootx .] + [winfo width .]/2 \
                                 - [winfo reqwidth .print]/2]
    set y [expr [winfo rooty .] + [winfo height .]/2 \
                                 - [winfo reqheight .print]/2]
    wm geometry .print +$x+$y
    wm deiconify .print 
    focus .print
}
#
# プリントアウト
#
proc print_child {} {
     global filename 
     global dvifilename 
     global output_to
     global dvi2ps_command
     global dvi2ps_option_start dvi2ps_option_end dvi2ps_option_paper
     global lpr_command
     global printer_name ps_file_name
     global ghostview_command ghostview_option ghostview_on
     global copy_number

     # 出力先がプリンターの場合
     if {$output_to == "printer"} { 
         wm withdraw .print 
         eval exec $dvi2ps_command \
                      -f $dvi2ps_option_start \
                      -t $dvi2ps_option_end   \
                      -o $dvi2ps_option_paper \
                         $dvifilename \
          | $lpr_command -\#$copy_number -P$printer_name

     # 出力先がファイルの場合
     } else {
         wm withdraw .print 
         eval exec $dvi2ps_command \
                      -f $dvi2ps_option_start \
                      -t $dvi2ps_option_end   \
                      -o $dvi2ps_option_paper \
                            $dvifilename > $ps_file_name

         # ghostview の起動
         if {$ghostview_on == 1} {
             eval exec $ghostview_command \
                            $ghostview_option $ps_file_name &
         }
     }
}


# Tk Widget の設定
toplevel .print
.print configure 
wm withdraw .print
wm transient .print .
#frame .print.dvi2ps_option 
#frame .print.lpr_option

frame .print.output    -relief raised -bd 2
frame .print.option    -relief raised -bd 2
frame .print.ghostview -relief raised -bd 2
frame .print.command   -relief raised -bd 2

label       .print.output.label  -text " 出力先" 

frame .print.output.1
radiobutton .print.output.1.radio -variable output_to \
                                  -value printer -text "プリンタ:" \
                              -command "set ghostview_on 0" 
entry       .print.output.1.entry -width 22 -relief sunken \
                                  -textvariable printer_name
pack \
       .print.output.1.radio \
       .print.output.1.entry \
                                -side left 
frame .print.output.2
radiobutton .print.output.2.radio -variable output_to \
                                  -value file -text "ファイル:"
entry       .print.output.2.entry -width 22 -relief sunken \
                                  -textvariable ps_file_name
pack \
       .print.output.2.radio \
       .print.output.2.entry \
                                -side left 
pack \
       .print.output.label \
       .print.output.1 \
       .print.output.2 \
                          -side top -anchor w


frame .print.option.main1
entry .print.option.main1.start   -width 9 -relief sunken \
                                  -textvariable dvi2ps_option_start 
label .print.option.main1.label1  -text " 〜 " 
entry .print.option.main1.end     -width 9 -relief sunken \
                                  -textvariable dvi2ps_option_end 
label .print.option.main1.label2  -text "頁" 

pack \
      .print.option.main1.start  \
      .print.option.main1.label1 \
      .print.option.main1.end    \
      .print.option.main1.label2 \
                                    -side left

frame .print.option.main2
label .print.option.main2.label1  -text "用紙:" 
entry .print.option.main2.paper   -width 7 -relief sunken \
                                  -textvariable dvi2ps_option_paper 
label .print.option.main2.label2  -text "  部数:" 
entry .print.option.main2.copy    -width 7 -relief sunken \
                                  -textvariable copy_number
pack \
      .print.option.main2.label1 \
      .print.option.main2.paper  \
      .print.option.main2.label2 \
      .print.option.main2.copy   \
                                    -side left


label .print.option.other -text "  その他の設定"

frame .print.option.dvi2ps 
label .print.option.dvi2ps.label -text "   dvi -> ps:"
entry .print.option.dvi2ps.entry -width 22 -relief sunken \
                                 -textvariable dvi2ps_command
pack \
      .print.option.dvi2ps.label \
      .print.option.dvi2ps.entry \
                                    -side left

frame .print.option.lpr
label .print.option.lpr.label    -text "   lpr:      "
entry .print.option.lpr.entry -width 22 -relief sunken \
                                 -textvariable lpr_command
pack \
      .print.option.lpr.label \
      .print.option.lpr.entry \
                                    -side left
pack \
      .print.option.main1  \
      .print.option.main2  \
                                -side top 
pack \
      .print.option.other  \
      .print.option.dvi2ps \
      .print.option.lpr    \
                                -side top -anchor w

label .print.ghostview.label -text "プレビューのため ghostview を起動"
frame .print.ghostview.radio
#label       .print.ghostview.radio.0 -text "  " 
radiobutton .print.ghostview.radio.1 -text "する" \
                              -command "set output_to file" \
                                     -variable ghostview_on -value 1
radiobutton .print.ghostview.radio.2 -text "しない" \
                                     -variable ghostview_on -value 0
pack \
      .print.ghostview.radio.1 \
      .print.ghostview.radio.2 -side left
frame .print.ghostview.option
label .print.ghostview.option.label -text "オプション:"
entry .print.ghostview.option.entry -width 23 -relief sunken \
                                    -textvariable ghostview_option
pack .print.ghostview.option.label \
     .print.ghostview.option.entry -side left
pack \
     .print.ghostview.label  \
                               -side top 
pack \
     .print.ghostview.radio  \
     .print.ghostview.option 

button .print.command.child  \
             -text "   出力   " \
             -command {print_child } 

button .print.command.cancel  \
             -text "キャンセル" -command "wm withdraw .print" 

pack \
     .print.command.child \
     .print.command.cancel \
                               -side left -padx 15 -pady 5 

pack \
     .print.output    \
     .print.option    \
     .print.ghostview \
     .print.command \
           -side top -anchor w -fill x 

# バインディング
bind .print <Return> { print_child }

##################################
#   コンパイルコマンド変更関係   #
##################################

toplevel .latex_command
wm withdraw .latex_command
wm transient .latex_command .

frame  .latex_command.close -relief groove -bd 3
button .latex_command.close.1 -text "  閉じる  " \
                 -command "wm withdraw .latex_command"
pack .latex_command.close.1 -padx 100 -pady 5

label .latex_command.label1 -text "コンパイルコマンド"
frame .latex_command.command
label .latex_command.command.1 -text " "
entry .latex_command.command.2 -textvariable latex_command -width 20
pack  .latex_command.command.1 \
      .latex_command.command.2 -side left

label .latex_command.label2 -text "コンパイルファイル(拡張子無しで)"
frame .latex_command.file
label .latex_command.file.1 -text " "
entry .latex_command.file.2 -textvariable dvifilename -width 40
pack  .latex_command.file.1 \
      .latex_command.file.2 -side left

pack  .latex_command.label1  \
      .latex_command.command \
      .latex_command.label2  \
      .latex_command.file    \
      .latex_command.close   \
                  -side top -anchor w

bind .latex_command <Return> { wm withdraw .latex_command }

proc change_compile_command { } {
    set x [expr [winfo rootx .] + [winfo width .]/2 \
                                 - [winfo reqwidth .latex_command]/2]
    set y [expr [winfo rooty .] + [winfo height .]/2 \
                                 - [winfo reqheight .latex_command]/2]
    wm geometry .latex_command +$x+$y
    wm deiconify .latex_command
    focus .latex_command
}

######################################
#   Tab による補完オンオフ変更関係   #
######################################

toplevel .tab_complement
wm withdraw .tab_complement
wm transient .tab_complement .

frame  .tab_complement.close -relief groove -bd 3
button .tab_complement.close.1 -text "  閉じる  " \
                 -command "wm withdraw .tab_complement"
pack .tab_complement.close.1 -padx 70 -pady 5

label .tab_complement.label1 -text "Tab によるコマンド・環境名補完を"
frame .tab_complement.onoff
radiobutton .tab_complement.onoff.on  -variable do_complement \
                                      -value 1 -text "する"
radiobutton .tab_complement.onoff.off -variable do_complement \
                                      -value 0 -text "しない"
pack  .tab_complement.onoff.on \
      .tab_complement.onoff.off -side left -padx 20

pack  .tab_complement.label1 \
      .tab_complement.onoff \
                      -side top -pady 3
pack  .tab_complement.close -side top 

bind .tab_complement <Return> { wm withdraw .tab_complement }

proc change_complement { } {
    set x [expr [winfo rootx .] + [winfo width .]/2 \
                                 - [winfo reqwidth .tab_complement]/2]
    set y [expr [winfo rooty .] + [winfo height .]/2 \
                                 - [winfo reqheight .tab_complement]/2]
    wm geometry .tab_complement +$x+$y
    wm deiconify .tab_complement
    focus .tab_complement
}

##############################################
#   タイプミスチェック機能オンオフ変更関係   #
##############################################

toplevel .latex_check
wm withdraw .latex_check
wm transient .latex_check .

frame  .latex_check.close -relief groove -bd 3
button .latex_check.close.1 -text "  閉じる  " \
                 -command "wm withdraw .latex_check"
pack .latex_check.close.1 -padx 70 -pady 5

label .latex_check.label1 -text "タイプミスチェック機能"
frame .latex_check.onoff
radiobutton .latex_check.onoff.on  -variable latex_check_on \
                                      -value 1 -text "オン"
radiobutton .latex_check.onoff.off -variable latex_check_on \
                                      -value 0 -text "オフ"
pack  .latex_check.onoff.on \
      .latex_check.onoff.off -side left -padx 20

pack  .latex_check.label1 \
      .latex_check.onoff \
                      -side top -pady 3
pack  .latex_check.close -side top 

bind .latex_check <Return> { wm withdraw .latex_check }

proc change_latex_check { } {
    set x [expr [winfo rootx .] + [winfo width .]/2 \
                                 - [winfo reqwidth .latex_check]/2]
    set y [expr [winfo rooty .] + [winfo height .]/2 \
                                 - [winfo reqheight .latex_check]/2]
    wm geometry .latex_check +$x+$y
    wm deiconify .latex_check
    focus .latex_check
}

####################################
#   xdvi 関係
####################################

toplevel .xdvi 
wm withdraw .xdvi
wm transient .xdvi .
frame .xdvi.command -relief groove -bd 3
frame .xdvi.options
button .xdvi.command.ok  \
                 -text "   起動   " \
                 -command { wm withdraw .xdvi ; xdvi_start }

button .xdvi.command.cancel  \
                 -text "キャンセル" \
                 -command "wm withdraw .xdvi" 
frame .xdvi.options.paper
label .xdvi.options.paper.label \
                 -text "用紙："
entry .xdvi.options.paper.entry -width 15 -textvariable xdvi_paper
pack  .xdvi.options.paper.label \
      .xdvi.options.paper.entry -side left

label .xdvi.options.label -text "その他のオプション"
frame .xdvi.options.entry
label .xdvi.options.entry.1 -text " "
entry .xdvi.options.entry.2 -width 30 -textvariable xdvi_option
pack  .xdvi.options.entry.1 \
      .xdvi.options.entry.2 -side left

pack \
    .xdvi.options.paper \
    .xdvi.options.label \
    .xdvi.options.entry \
        -side top -anchor w
pack \
    .xdvi.command.ok \
    .xdvi.command.cancel \
        -side left -padx 15 -pady 5
   
pack \
     .xdvi.options \
     .xdvi.command \
        -side top 

bind .xdvi <Return> { wm withdraw .xdvi ; xdvi_start }

# Xdvi のポップアップ
proc xdvi_popup { } {
    set x [expr [winfo rootx .] + [winfo width .]/2 \
                                 - [winfo reqwidth .xdvi]/2]
    set y [expr [winfo rooty .] + [winfo height .]/2 \
                                 - [winfo reqheight .xdvi]/2]
    wm geometry .xdvi +$x+$y
    wm deiconify .xdvi
    focus .xdvi
}

##################################################
#   ghostview 関係
##################################################

toplevel .ghostview
wm withdraw .ghostview
wm transient .ghostview .
frame .ghostview.command -relief groove -bd 3
frame .ghostview.options
button .ghostview.command.ok  \
                 -text "   起動   " \
                 -command { wm withdraw .ghostview ; ghostview_start }

button .ghostview.command.cancel  \
                 -text "キャンセル" \
                 -command "wm withdraw .ghostview" 
entry .ghostview.options.entry \
                 -width 30 \
                 -textvariable ghostview_options
label .ghostview.options.label \
                 -text "起動時のオプション"

pack \
    .ghostview.options.label \
    .ghostview.options.entry \
        -side top -pady 3
pack \
    .ghostview.command.ok \
    .ghostview.command.cancel \
        -side left -padx 15 -pady 5
   
pack \
     .ghostview.options \
     .ghostview.command \
        -side top 

bind .ghostview <Return> { wm withdraw .ghostview ; ghostview_start }

# ghostview のポップアップ
proc ghostview_popup { } {
    set x [expr [winfo rootx .] + [winfo width .]/2 \
                                 - [winfo reqwidth .ghostview]/2]
    set y [expr [winfo rooty .] + [winfo height .]/2 \
                                 - [winfo reqheight .ghostview]/2]
    wm geometry .ghostview +$x+$y
    wm deiconify .ghostview
}

# ghostview の起動
proc ghostview_start { } {
     global filename
     global ghostview_command
     global ghostview_options
     eval exec $ghostview_command $ghostview_options &
}

##########################################
# ダイジェストウィンドウ関係
##########################################

# ウィンドウのポップアップ
proc digest_popup { } {
    global digest_popup_flag
    wm deiconify .digest
    #initialize_digest
    set digest_popup_flag 1
}

# コンパイル後に，AUX ファイルが更新されているかどうかを監視する
# 0.25 秒に一回で1分間(=240回)
proc start_watch_auxfile { } {
    global aux_time new_aux_time
    global num_check_auxfile
    global digest_popup_flag

    if {$digest_popup_flag==1} {
        set new_aux_time $aux_time
        set num_check_auxfile 1
        watch_auxfile
    }
}

proc watch_auxfile { } {
    global dvifilename
    global digest_popup_flag
    global aux_time
    global num_check_auxfile
     
    while {$num_check_auxfile < 240} {
        if {[file exists $dvifilename.aux]==1} { 
            set new_aux_time [file mtime $dvifilename.aux] 
            if {$new_aux_time > $aux_time} {
                initialize_digest
                .text insert 1.0 [.digest.aux get 1.0 end]
                set num_check_auxfile 1000
            }
        }
        after 250 { watch_auxfile }
    }
}


# イニシャライズ
proc initialize_digest { } {
    global para_num sec_num fig_num eqn_num
    global dvifilename
    global digest_aux

    .digest.text delete 1.0 end

    .text mark set digest_tag 1.0

    set para_num 1
    set sec_num  1

    if {[file exists $dvifilename.aux]==1} {
        # aux ファイルを読み込む
        .digest.aux delete 1.0 end
        set f [open $dvifilename.aux]
        .digest.aux insert 1.0 [read $f 10000000]
        close $f 
        # 読み込んだ aux ファイルを少し書き換える
        .digest.aux mark set insert 1.0
        set stop_flag 0
        while {$stop_flag==0} {
            set results [.digest.aux search -count char_len \
                      -regexp {(string\\p)|(\\space )} insert end]
            if {$results==""} {
                set stop_flag 1
            } else {
                .digest.aux mark set insert $results
                .digest.aux delete $results "$results +$char_len c"
            }
        }
        # 日本語検索が出来るように一つの変数に aux ファイルの内容を
        # たたきこむ
        set digest_aux [.digest.aux get 1.0 end]
    }
    
    # 検索開始
    set search_end 0
    while {$search_end == 0} {
        set start_index [.text search -forward -regexp \
      {(\\part\*?\{)|(\\chapter\*?)|(\\(sub)*((section)|(paragraph))\*?)|(^(\ )*$)} digest_tag end ]
      # {(\\part\*?\{)|(\\chapter\*?)|(\\(sub)*((section)|(paragraph))\*?)} digest_tag end ]

        if {$start_index ==""} { 
            set search_end 1 ;# 無かったら終わり
        } else {
            # あった場合，そこに行ってから場合分けのプロシージャへ
            .text mark set digest_tag $start_index
            digest_search_end
        }
    }
}

proc digest_search_end { } {
    global sec_num
    global para_num
    global section_conf

    # まず前の文字が def だったら何もしないで１文字進めて抜ける
    if {[.text get "digest_tag -4c" digest_tag]=="\\def"} {
        .text mark set digest_tag "digest_tag +1c"
        return
    }
    # 判断のため前の15文字ほど切り取る    
    set judge_char [.text get digest_tag "digest_tag +15c"]

    if {[string match {\\part\{*} $judge_char] == 1} {

    # section, subsection, subsubsection の場合
    } elseif {[string match {\\*section*} $judge_char] == 1} {
        # まずコマンド名の直後の｛を見つける
        set begin_bracket_index \
         [.text search -forward \{ digest_tag "digest_tag lineend"]
        # 無ければ抜ける
        if {$begin_bracket_index==""} { 
            .text mark set digest_tag "digest_tag +1c"
            return
        }
        #.text mark set digest_tag "$begin_bracket_index +1c"
        .text mark set digest_tag "$begin_bracket_index"
        # ｛があった場合，今度は｝を探す
        set end_bracket_index [digest_search_end_bracket]

        # 文字列を得る
        set sec_char   [.text get "$begin_bracket_index +1c" \
                                  "$end_bracket_index -1c"]
        # aux ファイルを調べて，ページ番号とsection番号を得る
        set results [get_digest_page_and_section $sec_char]
        set page [lindex $results 0]
        set section_num [lindex $results 1]
        .digest.text insert end $page
        .digest.text insert end "頁  "
        .digest.text insert end $section_num
        .digest.text insert end " "

        # 括弧の中身をダイジェストウィンドウに追加してタグづけ
        .digest.text insert end $sec_char
        .text tag add digest_section$sec_num digest_tag
        .digest.text insert end "\n"

        # .digest.text の方もタグづけし，ジャンプする bind を設定
        .digest.text tag add digest_section$sec_num \
                           "end -2c linestart" "end -2c lineend"
        eval .digest.text tag configure digest_section$sec_num \
                          -foreground blue
        eval [subst {.digest.text tag bind digest_section$sec_num \
                       <ButtonPress> {.text mark set insert \
                                       digest_section$sec_num.first 
                                       clear_mem_y
                                       cursor_put} }]
        eval [.digest.text tag bind digest_section$sec_num <Enter> \
                  {.digest.text configure -cursor hand2 }]
        eval [.digest.text tag bind digest_section$sec_num <Leave> \
                  {.digest.text configure -cursor top_left_arrow }]
        incr sec_num

    } elseif {[string match {\\paragraph*} $judge_char] == 1} {

    # 改行の場合
    } else {
        # 複数行の改行の場合，次の行が空でないところまで先に進める
        set loop_end 0
        while {$loop_end == 0} {
            set blank [.text get "digest_tag lineend +1c" \
                                 "digest_tag lineend +1c lineend"]
            if {[regexp {^(\ )*$} $blank]==1} {
                .text mark set digest_tag "digest_tag lineend +1c"
            } else { 
                set loop_end 1
            }
        }

        if {([.text get "digest_tag lineend +1c" \
                        "digest_tag lineend +2c"]!="\\") && \
            ([.text get "digest_tag lineend +1c" \
                        "digest_tag lineend +2c"]!="%")  && \
            ([.text get "digest_tag lineend +1c" \
                        "digest_tag lineend +2c"]!="\n") && \
            ([.text get "digest_tag lineend +1c" \
                        "digest_tag lineend +2c"]!="\}") } {
            #.text mark set insert digest_tag
            .digest.text insert end "              "
            .digest.text insert end \
               [.text get "digest_tag lineend +1c" \
                          "digest_tag lineend +1c lineend"]
            .digest.text insert end "..."
            .digest.text insert end "\n"

            # メインテキストの方にタグ付け
            .text tag add digest_para$para_num digest_tag

            # .digest.text の方もタグづけし，ジャンプする bind を設定
            .digest.text tag add digest_para$para_num \
                    "end -2c linestart + 14c " "end -2c lineend"
            eval [subst {.digest.text tag bind digest_para$para_num \
                       <ButtonPress> {.text mark set insert \
                    "digest_para$para_num.first lineend +1c" 
                                          clear_mem_y
                                          cursor_put} }]
            eval [.digest.text tag bind digest_para$para_num <Enter> \
                      {.digest.text configure -cursor hand2 }]
            eval [.digest.text tag bind digest_para$para_num <Leave> \
                      {.digest.text configure -cursor top_left_arrow }]
            incr para_num

        }
    }
    # １文字分だけ進める
    .text mark set digest_tag "digest_tag +1c"
}

# 閉じ括弧を探す
proc digest_search_end_bracket { } {

    .text mark set digest_open_start digest_tag
    .text mark set digest_close_start digest_tag

    set open {(^|[^\\])\{} 
    set close {((^)|([^\\]))\}}

    set stop 0
    while {$stop == 0} { 
       set tmp [.text search -forward -count word_len \
                          -regexp ${close} digest_close_start end]
       if {$tmp == ""} { return }
       .text mark set digest_close_index $tmp
       set results [.text search -forward -regexp ${open} \
                        digest_open_start digest_close_index ]
       if {$results == ""} { 
           set stop 1
       } else {
           .text mark set digest_close_start "digest_close_index +1c"
           .text mark set digest_open_start "$results +1c"
       }       
    }
    return [.text index "digest_close_index +$word_len c"]
    #.text tag add $tag $start_index "close_index +$word_len c"
}

# AUX ファイルからページ番号と節番号を割り出す
proc get_digest_page_and_section { sec_char } {
    global digest_aux
    global dvifilename

    set page "?"
    set section_num "?"

    if {[file exists $dvifilename.aux]==0} { 
        return "$page $section_num"
    }

    # sec_char があるか探す
    set results [string first $sec_char $digest_aux]
    # sec_char の長さも調べておく
    set char_len [string length $sec_char]

    #.text insert 1.0 "\n"
    #.text insert 1.0 "\n"
    #.text insert 1.0 $digest_aux
    #.text insert 1.0 "\n"
    #.text insert 1.0 $sec_char
    #.text insert 1.0 "\n"
    #.text insert 1.0 "\n"
    #.text insert 1.0 "\n"
        
    # 無ければすぐ抜ける
    if {$results=="-1"} { return "$page $section_num" }

    # ある場合，そこから section_num, page を得るために
    # 括弧の位置を探す

    # まず results までの文字を word_fore に格納
    set word_fore [string range $digest_aux 0 [expr $results -1] ]
    # 開き括弧を探す
    set open_brace  [string last \{ $word_fore]
    # 閉じ括弧を探す
    set close_brace [string last \} $word_fore]
    # 節番号を得る
    set section_num [string range $word_fore $open_brace $close_brace]
    #.text insert 1.0 "\n"
    #.text insert 1.0 "\n"
    #.text insert 1.0 "\n"
    ##.text insert 1.0 $word_fore
    #.text insert 1.0 $digest_aux
    #.text insert 1.0 "\n"
    #.text insert 1.0 $results
    #.text insert 1.0 "\n"
    #.text insert 1.0 $sec_char

    # 次いで results 以降の文字を得る
    set word_back [string range $digest_aux \
                            [expr $results + $char_len +1] end]
    # 開き括弧を探す
    set open_brace  [string first \{ $word_back]
    # 閉じ括弧を探す
    set close_brace [string first \} $word_back]
    # ページ番号を得る
    set page [string range $word_back [expr $open_brace  +1] \
                                     [expr $close_brace -1]]

    # 同じ名前の場合に重複しないよう digest_aux の前の部分を削っておく
    set digest_aux $word_back

    return "$page $section_num"
}
