ReIndent Selection problem with {} used for variables and blocks

Syntax highlighting, code folding, brace matching, code indenting, and function list

ReIndent Selection problem with {} used for variables and blocks

Postby NeroMorte » Thu Jul 09, 2009 5:08 pm

This is what I'm using for WORDFILE.UEW, if you need to see full syntax file let me know please.

Code: Select all
/L14"MacroQuest2" Line Comment = |: Block Comment On = |* Block Comment Off = *| Escape Char = \ String Chars = " File Extensions = MAC INC
/Delimiters = ~!@%^&*()-+=|\/{}[]:;"'<>,.?
/Function String = "%Sub[ ^t*]+^([a-zA-Z_0-9]+^)"
/Indent Strings = "/for" "} else {" "{"
/Unindent Strings = "/next" "} else /" "} else {" "}" "/return"
/Open Brace Strings ="{" "(" "[" "${"
/Close Brace Strings ="}" ")" "]" "}"
/Ignore Strings SOL = "|*" "*|" "%^${^}"
/Open Fold Strings = "sub" "/if"
/Close Fold Strings = "/return" "}"

My problem is my if statements are little different then C++ here is example below. I'm trying to get the ReIndent Selection to work for my coding.

Code: Select all
Sub Sub_Name2
/if (!${Defined[Var]}) /varset Var value 0
/if (!${Defined[Var2]}) /varset Var2 value 0
/if (!${Defined[Var3]}) /varset Var3 value 0

/if (${Var} && !${Var2} && !${Var3}) {
  /call Sub_Name
  /if (${Var} == 1) {
    /do something
    /if (${Var2} == 0) {
      /do something
      /if (${Var3} == 0) {
        /do something
        /do something
      } else {
        /echo something else
      }
    }
  } else {
    /do something
    /do something
  }
} else /if (${Var} && ${Var2} && ${Var3} != 1) {
  /if (${Var}) /echo message
}

/for x 1 to ${Math.Calc[${Timer}+1]}
   /if (${x} == 101) /echo Timer Finished.
/next x

/if (${Var.Equal[${Me.Name}]} && ${Math.Calc[${pTarget[${pName}].Y}+10]} && !${Math.Calc[${pTarget[${pName}].X}+10]}) /echo Not within the X Location.
/return

Above is how I would like it to indent, format like, below is the results I'm getting.

Code: Select all
Sub Sub_Name2
/if (!${Defined[Var]}) /varset Var value 0
/if (!${Defined[Var2]}) /varset Var2 value 0
/if (!${Defined[Var3]}) /varset Var3 value 0

/if (${Var} && !${Var2} && !${Var3}) {
/call Sub_Name
/if (${Var} == 1) {
/do something
/if (${Var2} == 0) {
/do something
/if (${Var3} == 0) {
/do something
/do something
} else {
/echo something else
   }
   }
} else {
   /do something
   /do something
   }
} else /if (${Var} && ${Var2} && ${Var3} != 1) {
   /if (${Var}) /echo message
   }

   /for x 1 to ${Math.Calc[${Timer}+1]}
   /if (${x} == 101) /echo Timer Finished.
   /next x

   /if (${Var.Equal[${Me.Name}]} && ${Math.Calc[${pTarget[${pName}].Y}+10]} && !${Math.Calc[${pTarget[${pName}].X}+10]}) /echo Not within the X Location.
   /return

More examples:

Code: Select all
/if (${Var1} || ${var2}) {
   
   /if (${Math.Calc[${Target.Distance}].Int} < ${Math.Calc[${Var5}-2].Int}) {
      /if (${var4.Active} && !${Var3}) /stick moveback ${Math.Calc[${Var5}+4]}
   }

   /if (${Math.Calc[${Target.Distance}].Int} > ${Math.Calc[${Var5}-2].Int}) {
      /if (${var4.Active} && !${Var3}) /stick uw ${Var5}
   }

}


Code: Select all
/if (${Var1}) {
   /if (${Spawn[${Var1}].ID}) {
      /call ChatOut 4 "${Message1}"
   } else {
      /call ChatOut 4 "${Message2}"
      /return
   }
}


Code: Select all
/if (${CommandParam.Find[-ini]}) {
   /if (${Select[${VarName},${Ini["${IniFile}","${Section}"].Replace["|",","].Left[-2]}]}) {
      /ini "${IniFile}" "${Section}" "${VarName}" "${Value}"
   }
}


Code: Select all
/if (${Var1}) {
   /if (${${sList}.Length}) {
      /varset ${sList} ${${sList}}${sDiv}${sElement}
   } else {
      /varset ${sList} ${sElement}
   }
}


Code: Select all
/if (${Var1}) {
   /if (${Var2} && ${Spawn[id ${QuickID}].Class.SubClass} && ${Spawn[id ${QuickID}].Class.ID}) {
      /if (${Spawn[id ${QuickID}].Class.PctPCs}<${Var3}) {
         /call SubRoute ${Spawn[${QuickID}].Class.ID} "${Var4}" "${Message}"
      }
   }
}


Code: Select all
/if (!${Var1}) {
   /if ((${Var2}<95 || ${Var3}) && !${Me.Slot["${Var4}"].ID} && ${Me.Ready["${Var4}"]}) {
      /do something
   }
}


Code: Select all
/if (${Var1.NotEqual[${Var1-DefaultValue}]}) {

   /if (${Var2} || ${Var3}) /return
   /if (!${Var4}) {
      /if (!${Var5}) /return

      /for ArgNum 1 to ${Math.Calc[${Var1.Count[|]}+1]}
         /varset CommandParam ${Var1.Arg[${ArgNum},|]}
      /if (${Me.Slot[${CommandParam}].ID} == NULL) {
         /call Check "${CommandParam}" "${Var6}"
         /varset Var7 ${Spawn[${Var8}].ID}
         /call Check "${CommandParam}" "${Var7}"

         /if (${Sub.Return.Equal[Ready]}) /call MQ2 "${CommandParam}" "${Var9}" 7s "${Var6}" "${Var10}"
      /next ArgNum
      }
      /next ArgNum
   }
   
}


Code: Select all
/if (${Defined[Var1]}) {
   /varset GenStr |${Var1.Lower}|
   /if (${GenStr.Find[|${CurrCommand.Lower}|]}) {
      /echo doing sCut ${CommandText}
      /call sCut "${CommandText}"
      /return
   }
}

Is this problem something I can fix with the WORDFILE.UEW?

If anyone need any more information let me know. I tried to give a good example with Sub and if statements in it and what it's doing for me.
NeroMorte
Newbie
 
Posts: 3
Joined: Thu Jul 09, 2009 4:31 pm

Re: ReIndent Selection problem with {} used for variables and blocks

Postby Mofi » Fri Jul 10, 2009 12:58 pm

I played very, very long with various indent/unindent settings, but nothing worked perfect. Using auto-indent for your language is no problem. But the ReIndent Selection feature failed all the time. I had also no success with using Artistic Style to get your code formatted as you like. The reason is always the usage of { and } around variables. Whether the ReIndent Selection feature nor Artistic Style can handle this correct.

But finally I found a solution for you. Use following in your wordfile with tab replaced by a tab character:

/L14"MacroQuest2" Line Comment = |: Block Comment On = |* Block Comment Off = *| Escape Char = \ String Chars = " File Extensions = MAC INC
/Delimiters = ~ !tab@%^&*()-+=|\/{}[]:;"'<>,.?
/Function String = "%Sub[ ^t*]+^([a-zA-Z_0-9]+^)"
/Indent Strings = "/for" "{"
/Unindent Strings = "/next" "}" "/return"
/Open Brace Strings = "{" "(" "[" "${"
/Close Brace Strings = "}" ")" "]" "}"
/Ignore Strings SOL = "|*" "*|"
/Open Fold Strings = "sub" " {"
/Close Fold Strings = "/return" " }"

Please note: No only the indent/unindent strings are modified. Please use really the block above.

For re-indenting a selection you can't use the ReIndent Selection command. Instead use the macro below with the macro property Continue if search string not found checked. Here is the explanation of the macro.

First the macro checks if there is currently a selection when starting the macro. If this is the case it cuts the selection to clipboard 9, inserts the character þ (byte code 254) as marker for start of the selection, pastes the selection back and inserts character ÿ (byte code 255) as marker for end of the selection. If there is no selection on macro start, the macro inserts these two characters at bottom and top of the file and selects the entire file content.

Now a loop is executed which is defined as endless loop, but of course is not an endless loop. The main task of this loop is to replace all {} of the variables by «» in the current selection only. The regular expression string ^${^([~}^p]+^)} in UltraEdit syntax means:

  • ^$ ... find character $ which has a special regex meaning (end of line) and therefore must be escaped with ^ which is the escape character for UE syntax to be interpreted as normal character and without regex meaning.
  • { ... after $ the character { must follow.
  • ^(...^) ... means tag the string found by the expression inside ^(...^) for being re-used in the replace string. We want to keep the variable names.
  • [~}^p]+ ... means find any character 1 or more times which are whether a { nor a CRLF pair. So this expression selects everything after ${ to next } or end of line (for security because a negative character range does not stop at end of line).
  • } ... after the string not containing } the character } must follow. So a ${ without a matching } on the same line is ignored.
The replace string keeps the string between ${...}, and replaces { by « and { by ».

This replace all in current selection is now done in a loop until the search can't find anymore the expression ${...}. This is necessary because of nesting the variables. The replace does not first replace {} around the inner variables and then those of the outer variables. It replaces on first run ${ of the outer variable and the } of the inner variable and on second run ${ of the inner variable with } of the outer variable. But that does not matter. At end all ${...} around variables are converted to $«...».

Between every replace the selection must be restored. I don't know why UltraEdit sometimes keep the selection after the replace all inside the selection, which does not change the number of bytes selected, and sometimes it looses the selection. So for security the macro always reselects the selection. This is definitely not good for speed, but your files are probably not very large.

However, after the loop the only remaining {} are those for the blocks. So after a final reselection the re-indent selection command can make its job without problems.

The final steps are moving the cursor to top of the file, replace all « back to { and all » back to }, delete the inserted "start of selection marker character" þ and also the "end of selection marker character" ÿ. The cursor is at end of the initial selection or end of the file after the macro has finished. If you want the cursor at top of the file or start of the initial selection, use following for the last 4 lines of the macro:

Find "ÿ"
Replace ""
Find Up "þ"
Replace ""

Here is the macro which needs the macro property Continue if search string not found checked.

InsertMode
ColumnModeOff
HexOff
UltraEditReOn
IfSel
Clipboard 9
Cut
"þ"
Paste
ClearClipboard
Clipboard 0
"ÿ"
Find Up Select "þ"
Else
Bottom
"ÿ"
Top
"þ"
SelectAll
EndIf
Loop 0
Find RegExp SelectText "^${^([~}^p]+^)}"
Replace All "$«^1»"
IfNotFound
ExitLoop
EndIf
EndSelect
Top
Find "þ"
Find Select "ÿ"
EndLoop
EndSelect
Top
Find "þ"
Find Select "ÿ"
ReIndentSelection
Top
Find "«"
Replace All "{"
Find "»"
Replace All "}"
Find "þ"
Replace ""
Find "ÿ"
Replace ""
User avatar
Mofi
Grand Master
Grand Master
 
Posts: 4062
Joined: Thu Jul 29, 2004 11:00 pm
Location: Vienna

Re: ReIndent Selection problem with {} used for variables and blocks

Postby NeroMorte » Wed Jul 15, 2009 5:53 pm

Thanks Mofi. I'm starting to understand it a little more now. The final script you gave me seems to work perfect. I applied it to a lot of my code and I cannot find a spot it didn't work in scanning though it quickly.

Thanks a lot for explaining each section out to me that helped a ton also.
NeroMorte
Newbie
 
Posts: 3
Joined: Thu Jul 09, 2009 4:31 pm

Re: ReIndent Selection problem with {} used for variables and blocks

Postby dburgess » Tue Sep 08, 2009 2:37 pm

Been trying to modify this a little for my own ReIndention use. But I seem to be getting stuck. I've isolated my problem down to the Find RegExp command. I've also reduced my marco to the small subset to try and figure out my problem.

Macro is:
InsertMode
ColumnModeOff
HexOff
Find RegExp SelectText "{[~}{^p]+}"

This marco will successfully highlight the string I am looking for, but everytime I try to add in "(" and ")" to isolate the text inside my curly braces { }, I can not get the command to select my text. I've tried a few variations, but can not seem to make them select the code that the expresion above selects.

Find RegExp SelectText "{([~}{^p]+)}"
Find RegExp SelectText "{^([~}{^p]+^)}"

I'm trying to get far enough along to add in the
Replace All "«^1»"

Right now I'm assuming the partheses are used to set a subset variable "^1" so the Replace All ends up effectivly removing my curly braces with the « and » characters. (Only working for matching { and } within the same line.)

My goal is to be able to properly reindent tcl code such as:

Code: Select all
if {$x == 100} {
    puts "Line 1"
} else {
    if {$x == 200} {
        puts "Line 2"
    }
}

Any help would be greatly appreciated. Thanks!
dburgess
Newbie
 
Posts: 5
Joined: Mon Aug 11, 2008 6:16 pm

Re: ReIndent Selection problem with {} used for variables and blocks

Postby Mofi » Wed Sep 09, 2009 12:18 am

Following worked perfect for your example code using UE v15.10.0.1031:

InsertMode
ColumnModeOff
HexOff
UltraEditReOn
IfSel
Clipboard 9
Cut
"þ"
Paste
ClearClipboard
Clipboard 0
"ÿ"
Find Up Select "þ"
Else
Bottom
"ÿ"
Top
"þ"
SelectAll
EndIf
Find RegExp SelectText "{^([~}{^p]+^)}"
Replace All "«^1»"
Top
Find "þ"
Find Select "ÿ"
ReIndentSelection
Top
Find "«"
Replace All "{"
Find "»"
Replace All "}"
Find "þ"
Replace ""
Find "ÿ"
Replace ""
User avatar
Mofi
Grand Master
Grand Master
 
Posts: 4062
Joined: Thu Jul 29, 2004 11:00 pm
Location: Vienna

Re: ReIndent Selection problem with {} used for variables and blocks

Postby dburgess » Wed Sep 09, 2009 9:14 am

Still not working for me. I am on version 15.10.0.1031, and I copied your marco exactly.
When I omit the ^( and ^) from the regular expression, (Find RegExp SelectText "{[~}{^p]+}") it works correctly, except everything inside the { }s is converted to "^1". :-)

Do I need to set my regexp somewhere to tell it to use perl format?

Thanks again for all the help and advice.
dburgess
Newbie
 
Posts: 5
Joined: Mon Aug 11, 2008 6:16 pm

Re: ReIndent Selection problem with {} used for variables and blocks

Postby Mofi » Wed Sep 09, 2009 10:01 am

I'm using the same version as you and the macro uses the UltraEdit regular expression engine enabled by the command UltraEditReOn.

Is your file a UNIX file opened without temporary conversion to DOS?

In this case you would need ^n instead of ^p in the regular expression search string. Or better you use ^r^n instead of ^p which should result in a working replace for all type of line terminations for this regular expression search string.

Of course the UltraEdit regular expression engine works with this search/replace strings only if you have not specified a different character than ^ as special (escape) character at Advanced - Configuration - Search - Miscellaneous.

You can also use the Perl engine as shown in the macro code below:

InsertMode
ColumnModeOff
HexOff
PerlReOn
IfSel
Clipboard 9
Cut
"þ"
Paste
ClearClipboard
Clipboard 0
"ÿ"
Find Up Select "þ"
Else
Bottom
"ÿ"
Top
"þ"
SelectAll
EndIf
Find RegExp SelectText "\{([^}{\r\n]+)\}"
Replace All "«\1»"
Top
Find "þ"
Find Select "ÿ"
ReIndentSelection
Top
Find "«"
Replace All "{"
Find "»"
Replace All "}"
Find "þ"
Replace ""
Find "ÿ"
Replace ""
User avatar
Mofi
Grand Master
Grand Master
 
Posts: 4062
Joined: Thu Jul 29, 2004 11:00 pm
Location: Vienna

Re: ReIndent Selection problem with {} used for variables and blocks

Postby dburgess » Wed Sep 09, 2009 10:17 am

I don't know how, why, or when, but I had removed the "^" from "Advanced - Configuration - Search - Miscellaneous". Putting it back made all the difference! I'm glad I had the error though, because I do work with both unix and dos file types, so your suggestion to use "^r^n " instead of "^p", will be very helpful.

Thanks again Mofi, you're the man!!
dburgess
Newbie
 
Posts: 5
Joined: Mon Aug 11, 2008 6:16 pm


Return to Syntax Highlighting