string indent
Das Paket StringIndent erweitert das Kommandoensemble string um den Unterbefehl indent.
Das Kommando string indent $src übergibt eine Zeichenkette mit sauberer Einrückung entlang Geschweifer Klammern und Gänsefüßchen, falls möglich:
% package require IndentString
0.2
% string indent [.t get 1.0 end-1chars]
proc unbind args {
foreach event {<Button-1>
<Double-Button-1>
<Shift-Button-1>
<B1-Motion>
<Triple-Button-1>} {
bind .t $event ""
}
}
%
Wenn auf eine öffnende Schweifklammer nicht unmittelbar ein Zeilenwechsel folgt, werden die Folgezeilen bis zur schließenden Schweifklammer bündig angeordnet. Wer das nicht will, benutzt den Schalter -nocosmetics wie hier:
% string indent -nocosmetics [.t get 1.0 end-1chars]
proc unbind args {
foreach event {<Button-1>
<Double-Button-1>
<Shift-Button-1>
<B1-Motion>
<Triple-Button-1>} {
bind .t $event ""
}
}
%
Eckige und runde Klammern werden – soweit ordentlich balanciert – berücksichtigt wie Schweifklammern. Um dies zu unterdrücken, dienen die Schalter -noparens und -nobrackets. Unzweideutige Abkürzungen sind möglich.
Falls die Zeichenfolge nicht sinnvoll eingerückt werden kann, wird sie unverändert zurückgegeben.
#
# file IndentString-0.2.tm
#
# extend new subcommand:
# string indent $str
# returns properly indented code
#
package require Tcl 8.6.1
package provide IndentString 0.2
namespace eval IndentString {
namespace import ::tcl::mathfunc::* ::tcl::mathop::*
}
proc IndentString::firstSplitIndex {src {start 0}} {
lassign [info level 0] recurse
set quote [string first \u0022 $src $start+1]
set brace [string first \u007b $src $start]
if {$quote >= 0 || $brace >= 0} then {
if {$quote < 0} then {
set index $brace
} elseif {$brace < 0} then {
set index $quote
} else {
set index [min $quote $brace]
}
set part0 [string range $src 0 $index]
if {[info complete $part0]} then {
$recurse $src [+ $index 1]
} else {
set index
}
} else {
return -1
}
}
proc IndentString::completePartLength src {
if {[string index $src 0] eq "\{"} then {
set char "\}"
} else {
set char \"
}
set li [split $src ""]
set indices [lsearch -exact -all $li $char]
foreach length $indices {
if {[info complete [string range $src 0 $length]]} break
set length -1
}
set length
}
proc IndentString::splitByLevels src {
lassign [info level 0] recurse
set i [firstSplitIndex $src]
if {$i < 0} then {
list $src
} else {
set tail [string range $src $i end]
set l [completePartLength $tail]
set body [string range $tail 0 $l]
set rest [string range $tail [+ $l 1] end]
list [string range $src 0 [- $i 1]]\
[$recurse [string range $body 1 end-1]]\
{*}[$recurse $rest]
}
}
proc IndentString::lfIndices str {
lsearch -all [split $str ""] \n
}
proc IndentString::notifyLevel {li {_result result} {level 0}} {
# for every lf write depth to external result
lassign [info level 0] recurse
upvar $_result result
foreach i [lfIndices [lindex $li 0]] {
lappend result $level
}
foreach {a b} [lrange $li 1 end] {
$recurse $a result [+ $level 1]
foreach i [lfIndices $b] {
lappend result $level
}
}
}
proc IndentString::listOfLevels src {
set result {}
set li [splitByLevels $src]
notifyLevel $li result
set result
}
proc IndentString::doIndentString {str args} {
set str1 $str
if {"-nobrackets" ni $args} then {
set strBrackets [string map [list \[ \{ \] \}] $str1]
if {[info complete $strBrackets]} then {
set str1 $strBrackets
}
}
if {"-noparens" ni $args} then {
# string indent -noparens $str
set strParens [string map [list ( \{ ) \}] $str1]
if {[info complete $strParens]} then {
set str1 $strParens
}
}
#
set li\
[splitByLevels\
[string map\
[list \\\\ __ \\\n "_\n" {\"} {{"}}]\
$str1]]
set levels [listOfLevels $li]
set lines [lmap x [split $str \n] {string trimleft $x " "}]
set result [lindex $lines 0]
foreach level $levels line [lrange $lines 1 end] {
append result \n [string repeat " " [- $level 1]] $line
}
cosmetics $result {*}$args
}
proc IndentString::indentStr {str args} {
foreach arg $args {
if {[string index $arg] ne "-" ||
$arg in {- -n -no}} then {
return -code error "bad option $arg\nstring indent [lrange [info level 1] 1 end]"
} else {
set idx [lsearch {-nobrackets -noparens -nocosmetics} $arg*]
if {$idx < 0} then {
return -code error "bad option $arg\nstring indent [lrange [info level 1] 1 end]"
} elseif {[string match $arg* -nobrackets]} then {
lset args $idx -nobrackets
} elseif {[string match $arg* -noparens]} then {
lset args $idx -noparens
} elseif {[string match $arg* -nocosmetics]} then {
lset args $idx -nocosmetics
}
}
}
if {![info complete $str]} then {
set str
} elseif {![catch {
set result [doIndentString $str {*}$args]
} err]} then {
set result
} else {
doIndentString $str -noparens -nobrackets {*}$args
}
}
proc IndentString::cosmetics {str args} {
# unindent closing brace
set str [regsub -all "(\\n *) \}" $str "\\1\}"]
# indent backslashed line continuations
set str [regsub -all {[^\\](?:\\\\)*\\\n} $str "& "]
# {[lsearch $args -noc*] >= 0}
if {"-nocosmetics" ni $args} then {
# switch -nocosmetis given
set str
} else {
# align "... {apfel
# birne
# citrone}"
alignBrace $str
}
}
proc IndentString::alignBrace str {
set pat {\n[^\n]*[{][^\s\}][^{}]+\n[^{}]+[}]}
if {[regexp -indices $pat $str range]} then {
lassign $range start end
set head [string range $str 0 $start]
set body [string range $str $start+1 $end]
set foot [string range $str $end+1 end]
#
set lines [split $body \n]
set line0 [lindex $lines 0]
set length [string last \u007b $line0]
set dist [string repeat " " $length]
set linesRest\
[lmap x [lrange $lines 1 end] {
set x " $dist[string trimleft $x]"
}]
append result $head $line0 \n [join $linesRest \n] $foot
} else {
set str
}
}
if {[info command ::tcl::string::indent] eq ""} then {
proc ::tcl::string::indent args {
::IndentString::indentStr [lindex $args end] {*}[lrange $args 0 end-1]
}
apply {
map {
dict set map indent ::tcl::string::indent
namespace ensemble configure string -map $map
}
} [namespace ensemble configure string -map]
}
11.3.2022
<< | Heimatseite | Verzeichnis | Stichworte | Autor | >>