 ;; ...with tunable indentation level inside of the loop-control-expressions.
 ;;
 ;; FIXME: Actually, now that I look at it, all line-continuation from inside
-;; of "syntactic" {...} strings is fubar.  It all gets overindented.
+;; of "syntactic" {...} strings is fubar.  It all gets overindented.  Even
+;; conditional expressions.
 ;;
 ;; Look at the TCL mode code & fix it.
 
 
-(defun jpw-indent-to-matching-brace (&optional offset)
+(defun jpw-tcl-indent-to-matching-brace (&optional offset)
   "Do not call this function directly.
+Evals to nil if it didn't indent.
 {jpw: 7/06}"
   (back-to-indentation)
-  (let ((old-indent-pos (point))
-        (matching-brace-col (if (jpw-back-to-matching '?{ '?})
-                                (current-column)))
-        (matching-brace-indent (progn (jpw-backward-extended-line)
-                                      (back-to-indentation)
-                                      (current-column)))
+  (let (matching-brace-col
+        matching-brace-indent
+        new-indent
+        in-a-conditional
         );; end bindings
-    (goto-char old-indent-pos)
+    (if (not offset)
+        (setq offset 0))
+
+    (save-excursion
+      (if (jpw-back-to-matching '?{ '?})
+          (progn 
+            (setq matching-brace-col (current-column))
+            (backward-word 1)
+            (setq in-a-conditional 
+                  (looking-at "\\(elseif\\|if\\|while\\)"))
+            )
+        );;end if
+      (jpw-backward-extended-line)
+      (back-to-indentation)
+      (setq matching-brace-indent (current-column))
+      );;end excursion
+
     (if matching-brace-col
-        (indent-to (+ matching-brace-indent offset))
+        (if in-a-conditional
+            (tcl-indent-command)
+          ;; else
+          (setq new-indent (+ matching-brace-indent offset))
+          (if (< new-indent (current-indentation))
+              (save-excursion 
+                (let ((indentp (progn (back-to-indentation)
+                                      (point)))
+                      (bolp (progn (beginning-of-line)
+                                   (point)))
+                      );; end vars
+                  (delete-region bolp indentp)
+                  );; end let
+                );; end excursion
+            )
+          (indent-to new-indent)
+          )
+      ;; else
+      nil
       )
     );;end let
   )
+
+
+(defsubst jpw-tcl-statement-data ()
+  ;; Return a 2-element list describing the statement at `point'.
+  (list (cond ((looking-at "catch") 'catch)
+              ((looking-at "elseif") 'elseif)
+              ((looking-at "for ") 'for)
+              ((looking-at "foreach") 'foreach)
+              ((looking-at "if") 'if)
+              ((looking-at "while") 'while)
+              (t 'other-tcl-statement))
+        (current-indentation))
+  )
+
+
+(defsubst jpw-tcl-analyze-brace-pair ()
+  ;; Return the indentation-information of the parent of a brace-pair, or nil
+  ;; if we're not currently looking at a "} {" pair.
+  ;; The "indentation-information" is a 3-element list containing (in order):
+  ;; 1. The column of the matching open-brace of this line
+  ;; 2. The indentation of the line containing the open-brace matching the
+  ;;    close-brace on this line.
+  ;; 3. A symbol indicating parent-statement.
+  ;; 4. The indentation of the parent-statement.
+  ;; 5. The location of the ?{ on the line of the parent-statement
+  (let ((fwd-bound (point))
+        matching-open-brace-line-indent
+        matching-open-brace-indent
+        last-matching-open-brace-column
+        parent-statement-info
+        );;end vars
+    (if (looking-at "} +{")
+        (progn
+          (setq matching-open-brace-line-indent (current-column)
+                matching-open-brace-indent 
+                (+ (current-column) (- (match-end 0) (match-beginning 0))))
+          (while (looking-at "} +{")
+            (if (jpw-back-to-matching '?{ '?} nil fwd-bound)
+                (setq last-matching-open-brace-column (current-column))
+              ;; else
+              ;; Move off-char in case `jpw-back-to-matching' didn't move
+              ;; point.   Otherwise, we risk an infinite loop. 
+              (forward-char -1)
+              )
+            (back-to-indentation)
+            )
+          (setq parent-statement-info (jpw-tcl-statement-data))
+          (append matching-open-brace-indent
+                  matching-open-brace-line-indent
+                  parent-statement-info ;; 2 elts.
+                  last-matching-open-brace-column)
+          );; end progn
+      ;;else
+      nil
+      );; end outermost-if
+    );; end let
+  )
+
+
+(defsubst jpw-tcl-compute-brace-pair-indent ()
+  ;; Computes the indentation to use for a "} {" pair.  Evals to nil if
+  ;; `point' isn't currently looking at /} +{/.
+  (let* ((indent-info (jpw-tcl-analyze-brace-pair))
+         (parent-type (nth 2 indent-info))
+         ) ;; end vars
+    (if parent-type
+        (cond
+         ;; for-loops get special handling.
+         ((eq parent-type 'for)
+          (if jpw-tcl-align-for-loop-braces
+              (nth 4 indent-info)
+            ;; else:
+            ;; Offset it from the "for" statement.
+            (+ jpw-tcl-for-loop-bracepair-offset (nth 3 indent-info))
+            )
+          );; end case: for
+         ;; Indent other known statements (if, foreach, while, and so on) so
+         ;; that the close-brace aligns with the first open-brace after the
+         ;; statmenet.
+         ((not (eq parent-type 'other-tcl-statement))
+          (nth 4 indent-info)
+          );; end case: other known statement.
+         ;; Default:  let normal TCL mode handle it.
+         (t
+          nil)
+         ) ;; end cond
+      ) ;; end if
+    ) ;; end let
+  )
+
+
+(defsubst jpw-tcl-compute-1starg-indent ()
+  ;; Find the indendation column of the 1st arg of a command.  Assumes that
+  ;; `point' is on the command, or on a \[ character.
+  ;; If there's only one word on the line after `point' (and before any '\\'
+  ;; and the end of the line), return 'nil'.
+  (and (re-search-forward "\\s *" (line-end-position) t)
+       (re-search-forward "\\S *" (line-end-position) t)
+       (re-search-forward "\\s *" (line-end-position) t)
+       (not (looking-at "\\\\\\s *$"))
+       (current-column)
+       )      ;;sdfqretfwe asdrewq
+  )
+
+
+(defsubst jpw-tcl-analyze-extended-line ()
+  ;; If the present line is part of a continued line, evaluates to a 5-element
+  ;; list containing: 
+  ;; 1. The type of parent statement;
+  ;; 2. The indentation of the 1st line in the statement;
+  ;; 3. The point where the 1st line in the statement starts;
+  ;; 4. The type of opening paren on the 1st line of the statement (or nil if
+  ;;    none);
+  ;; 5. The column of (4), or nil.
+  ;; If the present line isn't an extended line, evaluates to nil.
+  ;;
+  ;; This function does not change `point'.
+  (save-excursion
+    (if (jpw-backward-extended-line)
+        (let ((parent (progn (back-to-indentation)
+                             (jpw-tcl-statement-data))
+              );;end vars
+          (if (re-search-forward "[[{\(]" (line-end-position) t)
+              (append parent
+                      (current-indentation) 
+                      (line-beginning-position)
+                      (list (char-after) (current-column)))
+            ;; else
+            (append parent 
+                    (current-indentation) 
+                    (line-beginning-position)
+                    nil nil)
+            )
+          );; end let
+      ;; else 
+      nil
+      )
+    )
+  )
+
+
+(defsubst jpw-tcl-compute-extended-close-brace-indent ()
+  ;; Compute the indent for a line that starts with ?} and is part of an
+  ;; extended TCL statement.
+  ;; There are 3 cases, described below.
+  (let* ((extended-line-info (jpw-tcl-analyze-extended-line))
+         (statement-type (car extended-line-info))
+         );;end vars
+    (cond
+     ;; Case (a):
+     ;; The for-statement is the exception, of course.  If the
+     ;; previous line begins with a "} {" pair, align to the 1st
+     ;; "{" in the statement.  Otherwise, let TCL-mode handle
+     ;; things.
+     ((eq statement-type 'for)
+      (forward-line -1)
+      (back-to-indentation)
+      (if (looking-at "}\\s +{")
+          (nth 4 tmp-extended-line-info)
+        nil)
+      )
+     ;; Case (b):
+     ;; If we're looking at some non-conditional statement, then
+     ;; find the matching curly and align to it. 
+     ((eq statement-type 'other-tcl-statement)
+      (and (jpw-back-to-matching '?{ '?})
+           (current-column))
+      )
+     ;; Case (c):
+     ;; An if, while, catch, or other control statement should
+     ;; align the close to the statement.  Which is the default
+     ;; behavior - i.e. eval to nil.
+     ;;
+     ;; This also handles the case of a nil `extended-line-info' - i.e. this
+     ;; isn't part of an extended TCL statement.  We want the default TCL-mode
+     ;; behavior in this case, too.
+     (t nil)
+     ) ;; end cond
+    );;end let
+  )
+
+
+(defsubst jpw-tcl-compute-bracket-indent ()
+  ;; Find the matching "[".  Returns the column of the beginning of the second
+  ;; word after the "[".
+  ;; If the user disables this behavior, do nothing and eval to nil.
+  (if (and jpw-tcl-align-to-arg
+           (jpw-back-to-matching '?\[ '?\]))
+      (jpw-tcl-compute-1starg-indent)
+    ;; else:  Let TCL-mode handle it.
+    nil
+    )
+  )
+
+
+(defsubst jpw-tcl-compute-extended-line-indent (extended-line-info)
+  ;; Computes the indentation for an extended TCL statement.
+  ;; 
+  ;; EXTENDED-LINE-INFO must be non-nil; the behavior of this function is
+  ;; undefined otherwise.
+  (let ((old-pos (point))
+        (statement-type (car extended-line-info))
+        (statement-open-paren (nth 3 extended-line-info))
+        (statement-bolp (nth 2 extended-line-info))
+        nearest-open-grp
+        nearest-open-grp-bolp
+        open-grp-column
+        statement-starts-group
+        ) ;; end vars
+
+    (setq nearest-open-grp 
+          (re-search-backward "[[\({]" 
+                              (nth 2 extended-line-info)
+                              t))
+    (if nearest-open-grp
+        (setq open-grp-column (current-column)
+              nearest-open-grp-bolp (line-beginning-position)
+              ;; - Does the nearest paren/bracket/brace equal the one in the
+              ;;   parent? 
+              ;; - Is the start of the line the same as the start of the
+              ;;   parent line?
+              statement-starts-group (and (eq nearest-open-grp 
+                                              statement-open-paren)
+                                          (= nearest-open-grp-bolp 
+                                             statement-bolp))
+              )
+      )
+
+    ;; Some cases and their controlling conditionals.
+
+    ;; No enclosing paren/brace/bracket?  Nothing special to do.  Let the
+    ;; normal TCL mode handle things.
+    ;; Only continue if we're inside of a grouping (i.e. a
+    ;; paren/brace/bracket).
+    (if nearest-open-grp
+        ;; - Is this a for/foreach loop?
+        ;; - Does the nearest paren/bracket/brace equal the one starting the
+        ;;   loop? 
+        ;; - Is the nearest paren/bracket/brace on the line starting the loop?
+        (if (and statement-starts-group
+                 (or (eq statement-type 'for)
+                     (eq statement-type 'foreach)
+                     ))
+            ;; for/foreach loops require special handling.  Of course.
+            do-for-or-foreach-case
+
+          ;; else
+          ;; Indent by type of paren:
+          (if (eq nearest-open-grp '?\[)
+              ;; - A ?[ always has the same indent, regardless of context.
+              (jpw-tcl-compute-bracket-indent)
+
+            ;; else
+            ;; We must be inside of a (...) or {...} pair.
+            (if (re-search-forward "\\S " (line-end-position) t)
+                ;; Align to the 1st non-ws char after the paren.
+                (if (eq nearest-open-grp '?{)
+                    ;; For a curly, add an optional offset to the paren posn.
+                    (+ (current-column) jpw-tcl-some-offset)
+                  ;; else:
+                  ;; eq ?\(
+                  (current-column)
+                  );; end if search-for-1st-non-ws-char
+
+              ;; else
+              ;; Fallback:  Use the previous line's indent.
+              (goto-char old-pos)
+              (jpw-last-line-indentation)
+              );; end indent-handler-if
+            );;end if '?[
+
+          );;end if in-a-for-loop
+
+      );; end if nearest-open-grp
+    ) ;; end let
+  )
+
+
+(defsubst jpw-tcl-compute-group-internal-indent()
+      (let* ((nearest-open-grp (re-search-backward "[[\({]" 
+                                                   (nth 2 extended-line-info)
+                                                   t))
+             (statement-type (car extended-line-info))
+             (statement-open-paren (nth 3 tmp-extended-line-info))
+             );; end vars
+        );; end let
+  )
+
+
+(defun jpw-tcl-compute-enhanced-indent ()
+  "Compute a more syntactically-correct indent than the old TCL mode indent
+function does.
+{jpw: 11/06}"
+  (save-excursion
+    (back-to-indentation)
+    (let ((starting-char (char-after))
+          (eolp (line-end-position))
+          tmp-extended-line-info
+          );; end vars
+      (cond
+
+       ;; Case #1:  Are we looking at a ")"?
+       ((eq starting-char '?\))
+        ;; Find its matching "(" and align to it, always.
+        (if (jpw-back-to-matching '?\( '?\))
+            (current-indentation)
+          ;; else:  Let TCL-mode handle it.
+          nil
+          )
+        )
+
+       ;; Case #2:  Are we looking at a "]"?
+       ((eq starting-char '?\])
+        (jpw-tcl-compute-bracket-indent)
+        )
+
+       ;; Case #3 & #4: Closing curly-brace.
+       ((eq starting-char '?})
+        (if (looking-at "}\\s +{")
+            ;; Case #3:  We're starting a line off with a closing curly-brace
+            ;; followed by an open curly-brace.
+            (jpw-tcl-compute-brace-pair-indent)
+          ;; else:
+          ;; 
+          ;; We're looking at a "}" followed by something else.
+          ;; Case #4:  It's part of an extended line.
+          ;; {Note that `jpw-tcl-compute-brace-pair-indent' evals to nil if
+          ;; Case #4 isn't in effect.}
+          (jpw-tcl-compute-extended-close-brace-indent)
+          ) ;; end outer-if
+        )
+
+       ;; Case #5:  Are we looking at an extended line?
+       ((setq tmp-extended-line-info (jpw-tcl-analyze-extended-line))
+        (jpw-tcl-compute-extended-line-indent tmp-extended-line-info)
+        )
+
+       ;; Case #6:  Are we inside of the start, test, or next expressions of a
+       ;; multi-line for-loop?
+       ;;
+       ;; If so, align to the previous line's "{", plus a user-defined offset.
+       (nil
+        )
+
+       ;; Case #7:  Are we the first statement in the body of a for-loop (or
+       ;; foreach-loop) that starts itself with extended lines?
+       ;;
+       ;; If so, align to the parent "for" (or "foreach") statement plus
+       ;; tcl-indent-level plus an optional offset.
+       ;;
+       ;; Alternative:  have a control flag (e.g.
+       ;; "correct-stoopid-tcl-for-loop-indenting") and, if it's set, check for
+       ;; this case, and indent as described above but without any optional
+       ;; offset.
+       (nil
+        )
+
+      ) ;; end cond
+    ) ;; end let
+  ) ;; end excursion
+)
 
 
 (defun jpw-tcl-indent-new-comment-line (&optional soft)

  (unless comment-end-skip
    (set (make-local-variable 'comment-end-skip) 
         "[ 	]*\\(\\s>\\|\n\\)"))
  )
(remove-hook 'tcl-mode-hook 'tcl-enhance-indentation)
(add-hook 'tcl-mode-hook 'tcl-enhance-indentation)

  :group 'tcl)


;;:type:
  ;; One of: integer, number, string, regexp, character, hook,
  ;;         symbol, function, variable, boolean


(defcustom jpw-tcl-allow-comment-unindent t
  "When set to non-nil, allows the function `jpw-tcl-comment-indent-command'
to \"indent backward\".  By default, `jpw-tcl-comment-indent-command' ignores
comments with internal indentation deeper than the previous line.
{jpw: 7/06}"
  :type '(boolean variable)
  :group 'tcl)


(defcustom jpw-tcl-align-for-loop-braces nil
  "Used to control indentation of a TCL for-loop written in a certain style.

When writing complex TCL for-loops, some people like to put the body of each
clause on its own line, placing the separating \"} {\" on a line by itself.
Setting `jpw-tcl-align-for-loop-braces' to non-nil will align those close-open
braces like so:

    for { 
            ...
        } {
            ...
        } {
            ...
        } {
        :
        :
    }

Otherwise, indentation of the  \"} {\" lines is controlled by
`jpw-tcl-for-loop-bracepair-offset'.
{jpw: 7/06}"
  :type '(boolean variable)
  :group 'tcl)


(defcustom jpw-tcl-for-loop-bracepair-offset 0
  "Used to control indentation of a TCL for-loop written in a certain style.

This is the other way of controlling  complex TCL for-loops writtne in the
style described by `jpw-tcl-align-for-loop-braces'.  When
`jpw-tcl-align-for-loop-braces' is nil, the enhanced indenation engine will
align each \"} {\" line with the \"for\" statement\(1\), plus an additional
offset specified by this variable.  The default is 0, which means align with
the \"for\" statement\(1\).

If, for example, you set this to 2, your for-loop would look like this:

    for { 
          ...
      } {
          ...
      } {
          ...
      } {
        :
        :
    }

Otherwise, indentation of the \"} {\" lines is controlled by
`jpw-tcl-for-loop-bracepair-offset'.

\(1\) Well, this is *almost* true.  It really aligns the \"} {\" lines with the
*line* containing the \"for\" command.  Usually, though, the  \"for\" command
is the first thing on the line.
{jpw: 7/06}"
  :type '(integer variable)
  :group 'tcl)


(defcustom jpw-tcl-align-to-arg t
  "When indending, how to align continued statements enclosed in a \[ ... \]
pair.  When non-nil, aligns to the first word after the command in the
\[ ... \].  Otherwise, let `tcl-mode' do the indendation.
{jpw: 7/06}"
  :type '(boolean variable)
  :group 'tcl)


