Updated 2014-10-14 05:55:35 by bharathan

Sarnold introduces here a script that provides this feature.

It works either as a command-line tool :
 tclsh reformat.tcl ?-indent number? myfile.tcl

and as a Tcl proc :
 source reformat.tcl
 set out [reformat $code]

Sarnold on 2008-04-05 : I fixed a bug that caused duplicating newlines. The -unixnl option was removed because of that bug. I added the -indent option to specify the number of blanks of the indentation.

NEM Could you describe what it does, exactly? Is it a pretty-printer for Tcl source code?

GWM it neatens any text file, correcting and setting indentations. A bug has been fixed in handling lines with multiple braces in them (eg "} else {" or " } } }").

[PM] on 2009-08-20 : fixed a bug causing commented lines including braces to increase/decrease indent, and added a swap through a temporary file to avoid getting an empty file if something goes wrong.

[neatpick] on 2011-04-04: the reformatted file should have the same permissions as the original file.

reformat.tcl
proc reformat {tclcode {pad 4}} {
    set lines [split $tclcode \n]
    set out ""
    set continued no
    set oddquotes 0
    set line [lindex $lines 0]
    set indent [expr {([string length $line]-[string length [string trimleft $line \ \t]])/$pad}]
    set pad [string repeat " " $pad]
    
    foreach orig $lines {
        set newline [string trim $orig \ \t]
        set line [string repeat $pad $indent]$newline
        if {[string index $line end] eq "\\"} {
            if {!$continued} {
                incr indent 2
                set continued yes
            }
        } elseif {$continued} {
            incr indent -2
            set continued no
        }

        if { ! [regexp {^[ \t]*\#} $line] } {

            # oddquotes contains : 0 when quotes are balanced
            # and 1 when they are not
            set oddquotes [expr {([count $line \"] + $oddquotes) % 2}]
            if {! $oddquotes} {
                set  nbbraces  [count $line \{]
                incr nbbraces -[count $line \}]
                set brace   [string equal [string index $newline end] \{]
                set unbrace [string equal [string index $newline 0] \}]
                if {$nbbraces>0 || $brace} {
                    incr indent $nbbraces ;# [GWM] 010409 multiple open braces
                }
                if {$nbbraces<0 || $unbrace} {
                    incr indent $nbbraces ;# [GWM] 010409 multiple close braces
                    if {$indent<0} {
                        error "unbalanced braces"
                    }
                    ## was: set line [string range $line [string length $pad] end]
                    # 010409 remove multiple brace indentations. Including case
                    # where "} else {" needs to unindent this line but not later lines.
                    set np [expr {$unbrace? [string length $pad]:-$nbbraces*[string length $pad]}]
                    set line [string range $line $np end]
                }
            } else {
                # unbalanced quotes, preserve original indentation
                set line $orig
            }
        }
        append out $line\n
    }
    return $out
}

proc eol {} {
    switch -- $::tcl_platform(platform) {
        windows {return \r\n}
        unix {return \n}
        macintosh {return \r}
        default {error "no such platform: $::tc_platform(platform)"}
    }
}

proc count {string char} {
    set count 0
    while {[set idx [string first $char $string]]>=0} {
        set backslashes 0
        set nidx $idx
        while {[string equal [string index $string [incr nidx -1]] \\]} {
            incr backslashes
        }
        if {$backslashes % 2 == 0} {
            incr count
        }
        set string [string range $string [incr idx] end]
    }
    return $count
}

set usage "reformat.tcl ?-indent number? filename"

if {[llength $argv]!=0} {
    if {[lindex $argv 0] eq "-indent"} {
        set indent [lindex $argv 1]
        set argv [lrange $argv 2 end]
    } else  {
        set indent 4
    }
    if {[llength $argv]>1} {
        error $usage
    }
    set f [open $argv r]
    set data [read $f]
    close $f
    set permissions [file attributes $argv -permissions]

    set filename "$argv.tmp"
    set f [open $filename  w]

    puts -nonewline $f [reformat [string map [list [eol] \n] $data] $indent]
    close $f
    file copy -force $filename  $argv
    file delete -force $filename
    file attributes $argv -permissions $permissions
}

GWM for interactive users I have created the code:
  # basic interface prompt for file and indent it by 2 spaces.
  # I am sure an interested reader will be able to make the indent adjustable too.
  set indent 2
  set fin [tk_getOpenFile -title "File to be reformatted"]
  set f [open $fin r]
  set data [read $f]
  close $f
  #console show; puts "Ho look at $fin" ;update idletasks
  set f [open ${fin}.txt w]
  puts -nonewline $f [reformat [string map [list [eol] \n] $data] $indent]
  close $f

ET the "} else {" in the #comment (below ## was:) seems to confuse the tcl interpreter, at least in my 8.6b1 it does; I'm guessing it is treating that as an end of block that happens to have a " at the end of it. I changed the 2 braces to something else and it quit complaining about a missing ".

[EP] I think that
                if {$nbbraces>0 || $brace} {
                    incr indent $nbbraces ;# [GWM] 010409 multiple open braces
                }
                if {$nbbraces<0 || $unbrace} {

should become
                if {$nbbraces!=0 || $brace || $unbrace}

to handle the following situation:
if { catch [ {
 ....
} } {
 ....
}

[srujan] - 2013-10-07 06:41:29

hi,

can you please fix the below errors in the reformat.tcl script

tclsh ../../reformat.tcl -indent 4 run-setup_aressim6_orig_indent missing "
    while compiling

"" needs to unindent this line but not later lines.
                    set np [expr {$unbrace? [string length $pad]:-$nbbraces*[string length $pad]}]

..."
    ("if" else script line 1)
    while compiling

"if {$nbbraces!=0 || $brace || $unbrace} {
                    incr indent $nbbraces ;# [GWM] 010409 multiple close braces
                    if {$ind..."
    ("if" then script line 6)
    while compiling

"if {! $oddquotes} {
                set  nbbraces  [count $line \{]
                incr nbbraces -[count $line \}]
                set brace   [strin..."
    ("if" then script line 6)
    while compiling

"if { ! [regexp {^[ \t]*\#} $line] } {
            # oddquotes contains : 0 when quotes are balanced
            # and 1 when they are not
           ..."
    ("foreach" body line 14)
    while compiling

"foreach orig $lines {
        set newline [string trim $orig \ \t]
        set line [string repeat $pad $indent]$newline
        if {[string index $li..."
    (compiling body of proc "reformat", line 10)
    invoked from within

"reformat [string map [list [eol] \n] $data] $indent"
    invoked from within

"if {[llength $argv]!=0} {
    if {[lindex $argv 0] eq "-indent"} {
        set indent [lindex $argv 1]
        set argv [lrange $argv 2 end]
    } els..."
    (file "../../reformat.tcl" line 81)

[srujan] - 2013-10-07 06:43:12

please fix the below errors
tclsh ../../reformat.tcl -indent 4 run-setup_aressim6_orig_indent
missing "
    while compiling
"" needs to unindent this line but not later lines.
                    set np [expr {$unbrace? [string length $pad]:-$nbbraces*[string length $pad]}]
..."
    ("if" else script line 1)
    while compiling
"if {$nbbraces!=0 || $brace || $unbrace} {
                    incr indent $nbbraces ;# [GWM] 010409 multiple close braces
                    if {$ind..."
    ("if" then script line 6)
    while compiling
"if {! $oddquotes} {
                set  nbbraces  [count $line \{]
                incr nbbraces -[count $line \}]
                set brace   [strin..."
    ("if" then script line 6)
    while compiling
"if { ! [regexp {^[ \t]*\#} $line] } {

            # oddquotes contains : 0 when quotes are balanced
            # and 1 when they are not
           ..."
    ("foreach" body line 14)
    while compiling
"foreach orig $lines {
        set newline [string trim $orig \ \t]
        set line [string repeat $pad $indent]$newline
        if {[string index $li..."
    (compiling body of proc "reformat", line 10)
    invoked from within
"reformat [string map [list [eol] \n] $data] $indent"
    invoked from within
"if {[llength $argv]!=0} {
    if {[lindex $argv 0] eq "-indent"} {
        set indent [lindex $argv 1]
        set argv [lrange $argv 2 end]
    } els..."
    (file "../../reformat.tcl" line 81)

[Durgaram] Corrected the code., now it is working fine for me
proc reformat {tclcode {pad 4}} {
    set lines [split $tclcode \n]
    set out ""
    set continued no
    set oddquotes 0
    set line [lindex $lines 0]
    set indent [expr {([string length $line]-[string length [string trimleft $line \ \t]])/$pad}]
    set pad [string repeat " " $pad]
    
    foreach orig $lines {
        set newline [string trim $orig \ \t]
        set line [string repeat $pad $indent]$newline
        if {[string index $line end] eq "\\"} {
            if {!$continued} {
                incr indent 2
                set continued yes
            }
        } elseif {$continued} {
            incr indent -2
            set continued no
        }

        if { ! [regexp {^[ \t]*\#} $line] } {

            # oddquotes contains : 0 when quotes are balanced
            # and 1 when they are not
            set oddquotes [expr {([count $line \"] + $oddquotes) % 2}]
            if {! $oddquotes} {
                set  nbbraces  [count $line \{]
                incr nbbraces -[count $line \}]
                set brace   [string equal [string index $newline end] \{]
                set unbrace [string equal [string index $newline 0] \}]
                if {$nbbraces>0 || $brace} {
                    incr indent $nbbraces ;# [GWM] 010409 multiple open braces
                }
                if {$nbbraces<0 || $unbrace} {
                    incr indent $nbbraces ;# [GWM] 010409 multiple close braces
                    if {$indent<0} {
                        error "unbalanced braces"
                    }
                    ## was: set line [string range $line [string length $pad] end]
                    # 010409 remove multiple brace indentations. Including case                   
                    set np [expr {$unbrace? [string length $pad]:-$nbbraces*[string length $pad]}]
                    set line [string range $line $np end]
                }
            } else {
                # unbalanced quotes, preserve original indentation
                set line $orig
            }
        }
        append out $line\n
    }
    return $out
}

proc eol {} {
    switch -- $::tcl_platform(platform) {
        windows {return \r\n}
        unix {return \n}
        macintosh {return \r}
        default {error "no such platform: $::tc_platform(platform)"}
    }
}

proc count {string char} {
    set count 0
    while {[set idx [string first $char $string]]>=0} {
        set backslashes 0
        set nidx $idx
        while {[string equal [string index $string [incr nidx -1]] \\]} {
            incr backslashes
        }
        if {$backslashes % 2 == 0} {
            incr count
        }
        set string [string range $string [incr idx] end]
    }
    return $count
}

set usage "reformat.tcl ?-indent number? filename"

if {[llength $argv]!=0} {
    if {[lindex $argv 0] eq "-indent"} {
        set indent [lindex $argv 1]
        set argv [lrange $argv 2 end]
    } else  {
        set indent 4
    }
    if {[llength $argv]>1} {
        error $usage
    }
    set f [open $argv r]
    set data [read $f]
    close $f
    set permissions [file attributes $argv -permissions]

    set filename "$argv.tmp"
    set f [open $filename  w]

    puts -nonewline $f [reformat [string map [list [eol] \n] $data] $indent]
    close $f
    file copy -force $filename  $argv
    file delete -force $filename
    file attributes $argv -permissions $permissions
}


 set indent 2
  set fin [tk_getOpenFile -title "File to be reformatted"]
  set f [open $fin r]
  set data [read $f]
  close $f
  #console show; puts "Ho look at $fin" ;update idletasks
  set f [open ${fin}.txt w]
  puts -nonewline $f [reformat [string map [list [eol] \n] $data] $indent]
  close $f

i used this code for indentation... working fine :)...

proc align {file} {
        set split_line 0
        set id [open $file r]
        set cont [read $id]
        close $id
        set id [open $file w+]
  set i 0
  set lines [split $cont \n]
  foreach line $lines {
    set line [string trim $line]
    if {$split_line} {
      for {set j [expr $i -2]} {$j>=0} {incr j -1} {
        puts -nonewline $id "  "
      }
      puts $id "          $line"
      if {[string index $line end] == "\\"} {
              set split_line 1
      } else {
              set split_line 0
      }
      set opens [regexp -all {\{} $line]
      set closes [regexp  -all {\}} $line]
      incr i [expr $opens - $closes]
      continue
    }
    if {[string index $line end] == "\\"} {
            set split_line 1
    } else {
      set split_line 0
    }
    if [regexp {\} else \{} $line] {
      for {set j [expr $i -2]} {$j>=0} {incr j -1} {
        puts -nonewline $id "  "
      }
      puts $id $line
      continue
    }
          set opens [regexp -all {\{} $line]
    set closes [regexp  -all {\}} $line]
          if {[expr $opens - $closes] == -1} {
                  incr i -1
                  for {set j [expr $i -1]} {$j>=0} {incr j -1} {
        puts -nonewline $id "  "
      }
      puts $id $line
      continue
          }
    for {set j [expr $i -1]} {$j>=0} {incr j -1} {
      puts -nonewline $id "  "
    }
    puts $id $line
    incr i [expr $opens - $closes]
  }
  close $id

}