|  | # git-gui simple class/object fake-alike | 
|  | # Copyright (C) 2007 Shawn Pearce | 
|  |  | 
|  | proc class {class body} { | 
|  | if {[namespace exists $class]} { | 
|  | error "class $class already declared" | 
|  | } | 
|  | namespace eval $class " | 
|  | variable __nextid     0 | 
|  | variable __sealed     0 | 
|  | variable __field_list {} | 
|  | variable __field_array | 
|  |  | 
|  | proc cb {name args} { | 
|  | upvar this this | 
|  | concat \[list ${class}::\$name \$this\] \$args | 
|  | } | 
|  | " | 
|  | namespace eval $class $body | 
|  | } | 
|  |  | 
|  | proc field {name args} { | 
|  | set class [uplevel {namespace current}] | 
|  | variable ${class}::__sealed | 
|  | variable ${class}::__field_array | 
|  |  | 
|  | switch [llength $args] { | 
|  | 0 { set new [list $name] } | 
|  | 1 { set new [list $name [lindex $args 0]] } | 
|  | default { error "wrong # args: field name value?" } | 
|  | } | 
|  |  | 
|  | if {$__sealed} { | 
|  | error "class $class is sealed (cannot add new fields)" | 
|  | } | 
|  |  | 
|  | if {[catch {set old $__field_array($name)}]} { | 
|  | variable ${class}::__field_list | 
|  | lappend __field_list $new | 
|  | set __field_array($name) 1 | 
|  | } else { | 
|  | error "field $name already declared" | 
|  | } | 
|  | } | 
|  |  | 
|  | proc constructor {name params body} { | 
|  | set class [uplevel {namespace current}] | 
|  | set ${class}::__sealed 1 | 
|  | variable ${class}::__field_list | 
|  | set mbodyc {} | 
|  |  | 
|  | append mbodyc {set this } $class | 
|  | append mbodyc {::__o[incr } $class {::__nextid]::__d} \; | 
|  | append mbodyc {create_this } $class \; | 
|  | append mbodyc {set __this [namespace qualifiers $this]} \; | 
|  |  | 
|  | if {$__field_list ne {}} { | 
|  | append mbodyc {upvar #0} | 
|  | foreach n $__field_list { | 
|  | set n [lindex $n 0] | 
|  | append mbodyc { ${__this}::} $n { } $n | 
|  | regsub -all @$n\\M $body "\${__this}::$n" body | 
|  | } | 
|  | append mbodyc \; | 
|  | foreach n $__field_list { | 
|  | if {[llength $n] == 2} { | 
|  | append mbodyc \ | 
|  | {set } [lindex $n 0] { } [list [lindex $n 1]] \; | 
|  | } | 
|  | } | 
|  | } | 
|  | append mbodyc $body | 
|  | namespace eval $class [list proc $name $params $mbodyc] | 
|  | } | 
|  |  | 
|  | proc method {name params body {deleted {}} {del_body {}}} { | 
|  | set class [uplevel {namespace current}] | 
|  | set ${class}::__sealed 1 | 
|  | variable ${class}::__field_list | 
|  | set params [linsert $params 0 this] | 
|  | set mbodyc {} | 
|  |  | 
|  | append mbodyc {set __this [namespace qualifiers $this]} \; | 
|  |  | 
|  | switch $deleted { | 
|  | {} {} | 
|  | ifdeleted { | 
|  | append mbodyc {if {![namespace exists $__this]} } | 
|  | append mbodyc \{ $del_body \; return \} \; | 
|  | } | 
|  | default { | 
|  | error "wrong # args: method name args body (ifdeleted body)?" | 
|  | } | 
|  | } | 
|  |  | 
|  | set decl {} | 
|  | foreach n $__field_list { | 
|  | set n [lindex $n 0] | 
|  | if {[regexp -- $n\\M $body]} { | 
|  | if {   [regexp -all -- $n\\M $body] == 1 | 
|  | && [regexp -all -- \\\$$n\\M $body] == 1 | 
|  | && [regexp -all -- \\\$$n\\( $body] == 0} { | 
|  | regsub -all \ | 
|  | \\\$$n\\M $body \ | 
|  | "\[set \${__this}::$n\]" body | 
|  | } else { | 
|  | append decl { ${__this}::} $n { } $n | 
|  | regsub -all @$n\\M $body "\${__this}::$n" body | 
|  | } | 
|  | } | 
|  | } | 
|  | if {$decl ne {}} { | 
|  | append mbodyc {upvar #0} $decl \; | 
|  | } | 
|  | append mbodyc $body | 
|  | namespace eval $class [list proc $name $params $mbodyc] | 
|  | } | 
|  |  | 
|  | proc create_this {class} { | 
|  | upvar this this | 
|  | namespace eval [namespace qualifiers $this] [list proc \ | 
|  | [namespace tail $this] \ | 
|  | [list name args] \ | 
|  | "eval \[list ${class}::\$name $this\] \$args" \ | 
|  | ] | 
|  | } | 
|  |  | 
|  | proc delete_this {{t {}}} { | 
|  | if {$t eq {}} { | 
|  | upvar this this | 
|  | set t $this | 
|  | } | 
|  | set t [namespace qualifiers $t] | 
|  | if {[namespace exists $t]} {namespace delete $t} | 
|  | } | 
|  |  | 
|  | proc make_dialog {t w args} { | 
|  | upvar $t top $w pfx this this | 
|  | global use_ttk | 
|  | uplevel [linsert $args 0 make_toplevel $t $w] | 
|  | pave_toplevel $pfx | 
|  | } | 
|  |  | 
|  | proc make_toplevel {t w args} { | 
|  | upvar $t top $w pfx this this | 
|  |  | 
|  | if {[llength $args] % 2} { | 
|  | error "make_toplevel topvar winvar {options}" | 
|  | } | 
|  | set autodelete 1 | 
|  | foreach {name value} $args { | 
|  | switch -exact -- $name { | 
|  | -autodelete {set autodelete $value} | 
|  | default     {error "unsupported option $name"} | 
|  | } | 
|  | } | 
|  |  | 
|  | if {$::root_exists || [winfo ismapped .]} { | 
|  | regsub -all {::} $this {__} w | 
|  | set top .$w | 
|  | set pfx $top | 
|  | toplevel $top | 
|  | set ::root_exists 1 | 
|  | } else { | 
|  | set top . | 
|  | set pfx {} | 
|  | } | 
|  |  | 
|  | if {$autodelete} { | 
|  | wm protocol $top WM_DELETE_WINDOW " | 
|  | [list delete_this $this] | 
|  | [list destroy $top] | 
|  | " | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | ## auto_mkindex support for class/constructor/method | 
|  | ## | 
|  | auto_mkindex_parser::command class {name body} { | 
|  | variable parser | 
|  | variable contextStack | 
|  | set contextStack [linsert $contextStack 0 $name] | 
|  | $parser eval [list _%@namespace eval $name] $body | 
|  | set contextStack [lrange $contextStack 1 end] | 
|  | } | 
|  | auto_mkindex_parser::command constructor {name args} { | 
|  | variable index | 
|  | variable scriptFile | 
|  | append index [list set auto_index([fullname $name])] \ | 
|  | [format { [list source [file join $dir %s]]} \ | 
|  | [file split $scriptFile]] "\n" | 
|  | } |