Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

SyntaxTidy cont´d


  • Please log in to reply
4 replies to this topic
Hajos
  • Members
  • 17 posts
  • Last active: Jul 10 2005 11:08 AM
  • Joined: 04 Jun 2005
Hi all,
Toralf generously conceded that I add to his work on SyntaxTidy he offered in http://www.autohotke...?t=2528&start=0
I gladly seized this license to add a few features - and thanks to Toralf for his work, and to all others who contributed ideas.
All further suggestions welcome. And of course all bug reports.

; Functionality:
; - Gui: For drag&drop of files, setting of options and feedback
; - Options:
; - custom file extension
; - custom indentation ( one tab or a number of spaces )
; - different indentation styles ( Rajat or Toralf )
; - indentation of continuation lines ( a number of tabs or spaces )
; - indentation preservation of block continuation lines ( round brackets ) On/Off
; - indentation preservation of block comments ( /* ... */ ) On/Off
; - case correction for syntax words with more than 3 characters ( thanks Rajat )
; - statistics for script ( lines of code, comments, total and empty )
; - Dropped Files: Contents will be indented and copied to a new file
; with a user defined extension.
; - ShortCut F2: ( thanks ChrisM ) Highlighted syntax in an editor
; will be indented, if nothing is highlighted all text will be indented.
; - Gui remembers last position and settings between sessions ( thanks Rajat )
; - The spelling of subroutine calls and function calls is adjusted to the spelling
; in their respective definitions
; - Win-Ctrl-d toggles dubug mode

; Recent changes:
; - case adjustment of labels and self defined functions
; - improved detection of one line if commands (avoid false positives)
; - improved indentation of comment lines
; - code restructured
; - only full word replacement, i.e. no longer replacement of _parts_ of a word which correspond to a keyword
; - no replacement in quoted text and commentaries
; - faster (about 4 to 5 times) - making the code rather envolved, though
; - case adjustment of ahk function names
; just in case: ---- !!!!!! Backup your data !!!!!
(the script has been tested on itself.)
OwnHotkey=F9
ScriptName =  Auto-Syntax-Tidy v6.1

; OS=WinXP, AHK=1.0.35.16, Author = Toralf, Co-Author = Hajos
; 2005-06-09, 2005-06-27, 2005-07-10
;
; What it does:
; It takes an AHK script and changes the indentation and case of keywords according to syntax.
;
; Known limitations:
;  - a space is required before the "(" in an if-statement expression
;  - case correction only for names longer than 3 characters
;  - after doing indentation in an editor the cursor jumps
;      to the first position in the last line
;  - sparsely commented
;
; Functionality:
;  - Gui: For drag&drop of files, setting of options and feedback
;  - Options:
;          - custom file extension
;          - custom indentation ( one tab or a number of spaces )
;          - different indentation styles ( Rajat or Toralf )
;          - indentation of continuation lines ( a number of tabs or spaces )
;          - indentation preservation of block continuation lines ( round brackets ) On/Off
;          - indentation preservation of block comments ( /* ... */ ) On/Off
;          - case correction for syntax words with more than 3 characters ( thanks Rajat )
;          - statistics for script ( lines of code, comments, total and empty )
;  - Dropped Files: Contents will be indented and copied to a new file
;                  with a user defined extension.
;  - ShortCut F2: ( thanks ChrisM ) Highlighted syntax in an editor
;        will be indented, if nothing is highlighted all text will be indented.
;  - Gui remembers last position and settings between sessions ( thanks Rajat )
;  - The spelling of subroutine calls and function calls is adjusted to the spelling
;                  in their respective definitions
;  - Win-Ctrl-d toggles dubug mode

; Recent changes:
;  - case adjustment of labels and self defined functions
;  - improved detection of one line if commands (avoid false positives)
;  - improved indentation of comment lines
;  - code restructured
;  - only full word replacement, i.e. no longer replacement of _parts_ of a word
;                 which correspond to a keyword
;  - no replacement in quoted text and commentaries
;  - faster (about 4 to 5 times) - making the code rather envolved, though
;  - case adjustment of  ahk function names

; just in case: ---- !!!!!! Backup your data !!!!!
;
; Suggestions are appreciated
;
#SingleInstance force
SetBatchLines, -1

Hotkey, %OwnHotkey%, IndentHighlightedText

DebugMode = 0    ;Turn DebugMode on ( =1 ) to show MsgBox with Debug Info

Gosub, ahk_specific

Gosub, Read_ahkSyntaxFiles

Gosub, BuildGUI

Return
;#############   End of autoexec section   ####################################
#^d::
   DebugMode := DebugMode = 0
   MsgBox, DebugMode = %DebugMode%
Return

;#############   ahk specific stuff   #########################################
ahk_specific:
   CommentChar := ";"
   BlockBegin := "{"
   BlockEnd := "}"
   BlockCommentBegin := "/*"
   BlockCommentEnd := "*/"
   ContBlockBegin := "("
   ContBlockEnd := ")"
Return

;#############   Read directives and commands from syntax file   ##############
Get_ahkdir:
   ;search for AHK directory, if not found take best guess.
   RegRead, ahk_dir, HKEY_LOCAL_MACHINE, SOFTWARE\AutoHotkey, InstallDir
   If ErrorLevel <> 0  ; Use a best guess location instead.
         ahk_dir = %ProgramFiles%\AutoHotkey
   ;   ahk_dir = C:\Programme\AutoHotkey
   IfNotExist %ahk_dir%
      {
         MsgBox Could not find the AutoHotkey folder.`nPlease Edit script.
         ExitApp
      }
Return

Read_ahkSyntaxFiles:
   Gosub, Get_ahkdir
   ;path to syntax files
   PathSyntaxFiles = %ahk_dir%\Extras\Editors\Syntax

   ;read each line of syntax file and collect directives and if-keywords
   Loop, Read, %PathSyntaxFiles%\CommandNames.txt   ;read syntax file
      {
         Line = %A_LoopReadLine%         ;trim spaces

         ;get first character and first 2 characters of line
         StringLeft, FirstChar, Line , 1
         StringLeft, FirstTwoChars, Line , 2

         If ( InStr( Line, ";" ) = 1 )         ;skip comments
               Continue
         ;otherwise if keyword is directive or if-keyword add it to list
         If ( InStr( Line, "#" ) = 1 )
               ListOfDirectives=%ListOfDirectives%%Line%,
         Else If ( InStr( Line, "if" ) = 1 )
            {
               ;get first word, since more words may follow after an If-keyword
               StringSplit, Word, Line, %A_Space%
               Line = %Word1%
               If Line not in %ListOfIfCommands%
                     ListOfIFCommands=%ListOfIFCommands%%Line%,
            }
      }
   Loop, Read, %PathSyntaxFiles%\Functions.txt   ; get ahk function names
      {
         BracketPos := InStr( A_LoopReadLine, "(" )
         If ( BracketPos )
            {
               StringLeft, Tfn, A_LoopReadLine, BracketPos
               ahk_functions = %ahk_functions%,%Tfn%
            }
      }
   SyntaxFiles = CommandNames|Keywords|Keys|Variables
   ;process all syntax files
   Loop, Parse, SyntaxFiles, |
         %A_LoopField%0 := ListOfNames( PathSyntaxFiles, A_LoopField, ".txt", CommentChar )
Return

ListOfNames( Path, NameList, Ext, CommentChar )
   {
      local List, LineLength, GreatestLength
      Loop, Read, %Path%\%NameList%%Ext%      ;read each line of syntax file
         {
            Line = %A_LoopReadLine%                ;trim spaces

            ;get first character, length of line, and check for internal spaces
            StringLeft, FirstChar, Line , 1

            If ( InStr( Line, A_Space ) )    ;skip if line contains spaces
                  Continue
            If Line is Space                 ;skip empty lines
                  Continue
            If ( FirstChar = CommentChar )   ;skip comments
                  Continue
            If ( FirstChar = "#" )           ;skip directives
                  Continue
            StringLen, LineLength, Line
            If ( LineLength >= 3 )      ;store words longer than 3 characters
               {
                  List = %NameList%%LineLength%
                  %List% := %List% . Line . "|"
                  GreatestLength := AtLeast( LineLength, GreatestLength )
               }
         }
      Return  GreatestLength
   }

;#############   Build GUI for Auto-Syntax-Tidy   #############################
BuildGUI:
   LogText = Drop files to be indented`nor mark Text in editor and press %OwnHotkey%.`n`n
   IniRead, Extension, %ScriptName%.ini, Settings, Extension, _autoindent.ahk
   IniRead, Indentation, %ScriptName%.ini, Settings, Indentation, 2
   IniRead, NumberSpaces, %ScriptName%.ini, Settings, NumberSpaces, 2
   IniRead, NumberIndentCont, %ScriptName%.ini, Settings, NumberIndentCont, 8
   IniRead, Style, %ScriptName%.ini, Settings, Style, 2
   IniRead, CaseCorrectCommandNames, %ScriptName%.ini, Settings, CaseCorrectCommandNames, 1
   IniRead, CaseCorrectVariables, %ScriptName%.ini, Settings, CaseCorrectVariables, 1
   IniRead, CaseCorrectKeys, %ScriptName%.ini, Settings, CaseCorrectKeys, 1
   IniRead, CaseCorrectKeywords, %ScriptName%.ini, Settings, CaseCorrectKeywords, 1
   IniRead, CaseCorrectFunctions, %ScriptName%.ini, Settings, CaseCorrectFunctions, 1
   IniRead, statistics, %ScriptName%.ini, Settings, statistics, 1
   IniRead, KeepContIndent, %ScriptName%.ini, Settings, KeepContIndent, 0
   IniRead, KeepBlockCommentIndent, %ScriptName%.ini, Settings, KeepBlockCommentIndent, 0

   Gui, +ToolWindow +AlwaysOnTop
   Gui, Add, Text, xm Section , Extension for files
   Gui, Add, Edit, ys-3 r1 w117 vExtension, %Extension%

   Gui, Add, GroupBox, xm w210 r6.3, Indentation
   Gui, Add, Text, xp+8 yp+15 Section, Type:
   Gui, Add, Radio, ys vIndentation, 1xTab or
   Gui, Add, Radio, ys Checked, Spaces
   Gui, Add, Edit, ys-3 r1 Limit1 Number w15 vNumberSpaces, %NumberSpaces%
   Gui, Add, Text, xs Section, Style:
   Gui, Add, Radio, ys vStyle, Rajat or
   Gui, Add, Radio, ys Checked, Toralf
   Gui, Add, Text, xs Section, Indentation of continuation lines:
   Gui, Add, Radio, xs vIndentCont Section, Tabs or
   Gui, Add, Radio, ys Checked, Spaces
   Gui, Add, Edit, ys-3 r1 Limit2 Number w20 vNumberIndentCont, %NumberIndentCont%
   Gui, Add, Text, xs Section, Keep present indentation inside ...
   Gui, Add, Checkbox, xs Section vKeepBlockCommentIndent Checked%KeepBlockCommentIndent%, Block comments
   Gui, Add, Checkbox, ys vKeepContIndent Checked%KeepContIndent%, Cont´n blocks
   Gui, Add, GroupBox, xm w210 r2, Case-Correction for
   Gui, Add, Checkbox, xp+8 yp+18 Section vCaseCorrectCommandNames Checked%CaseCorrectCommandNames%, Commands
   Gui, Add, Checkbox, vCaseCorrectVariables Checked%CaseCorrectVariables%, Variables
   Gui, Add, Checkbox, ys vCaseCorrectKeys Checked%CaseCorrectKeys%, Keys
   Gui, Add, Checkbox, vCaseCorrectKeywords Checked%CaseCorrectKeywords%, Keywords
   Gui, Add, Checkbox, xp+50 ys vCaseCorrectFunctions Checked%CaseCorrectFunctions%, Functions
   Gui, Add, Text, xm Section, Information
   Gui, Add, Checkbox, ys vstatistics Checked%statistics%, statistics
   Gui, Add, Edit, xm r10 w210 vlog ReadOnly, %LogText%
   If ( Indentation = 1 )
         GuiControl, , 1xTab or, 1
   If ( Style = 1 )
         GuiControl, , Rajat, 1

   ;get previous position and show Gui
   IniRead, PosX_Gui, %ScriptName%.ini, General, PosX_Gui,
   IniRead, PosY_Gui, %ScriptName%.ini, General, PosY_Gui,
   Gui, Show, %PosX_Gui% %PosY_Gui%, %ScriptName%
Return

;#############   Shortcut %OwnHotkey% - indent highlighted text  ##############
IndentHighlightedText:
   WinGetActiveTitle, CurrTitle
   ClipSaved := ClipboardAll  ; Save and clear clipboard
   Clipboard =
   Send, ^c                   ; Copy highlighted text to clipboard
   If Clipboard is Space      ; If nothing is highlighted, select all
         Send, ^a^c
   ClipboardString := Clipboard
   If ClipboardString is not Space
      {
         Gosub, PrepareWork
         IndentText( ClipboardString )
         Clipboard := ClipboardString
         WriteLogInfo( "marked text" )

         WinActivate, %CurrTitle%
         WinWaitActive, %CurrTitle%
         ;paste clipboard
         Send, ^v{Home}
      }
   ;restore clipboard and free memory
   Clipboard := ClipSaved
   ClipSaved =
   ClipboardString =
Return

;#############   Process all dropped files   ##################################
GuiDropFiles:
   Gosub, PrepareWork

   Loop, Parse, A_GuiControlEvent, `n   ;process dropped files
      {
         OutFile = %A_LoopField%%Extension%

         FileRead, Text, %A_LoopField%

         IndentText( Text )

         ;paste file into new file
         ;  if Extension is empty, old file will be overwritten
         FileDelete, %OutFile%
         FileAppend, %Text%, %OutFile%
         WriteLogInfo( A_LoopField )
      }
   Text =
Return

;#############   Write log   ##################################################
WriteLogInfo( Name )
   {
      global
      LogText = %LogText%Indentation done for: %Name%`n
      If statistics
            Gosub, AddstatisticsToLog
      Else
            LogText = %LogText%`n
      GuiControl, , Log , %LogText%
   }

AddstatisticsToLog:
   ;calculate lines of code
   CodeLineCount := TotalLineCount - CommentLineCount - EmptyLineCount
   Now_msec := A_TickCount - Now_msec
   ;add information
   LogText = %LogText%=====statistics:=====`n
   LogText = %LogText%  Code Lines: %A_Tab%%A_Tab%%CodeLineCount%`n
   LogText = %LogText%  Comment Lines: %A_Tab%%A_Tab%%CommentLineCount%`n
   LogText = %LogText%  Empty lines: %A_Tab%%A_Tab%%EmptyLineCount%`n
   LogText = %LogText%Total Number of lines: %A_Tab%%TotalLineCount%`n   ;`n
   LogText = %LogText%Time elapsed [msec]: %A_Tab%%Now_msec%`n`n
Return

;#############   PrepareWork   ################################################
PrepareWork:
   Gui, Submit, NoHide                                       ;get Options

   CaseFlag := SetCaseCorrectNames( CaseFlag )

   Gosub, CreateIndentationUnits
Return

;#############   Set ahk name lists for case correction  ######################
SetCaseCorrectNames( CaseFlag )
   {
      local cn, cf, cni, MaxNameLength
      cf = 0
      Loop, Parse, SyntaxFiles, |
         {
            cf := ( cf << 1 ) + CaseCorrect%A_LoopField%
            MaxNameLength := AtLeast( MaxNameLength, %A_LoopField%0 )
         }
      ; rebuild all lists if current selection <> previous selection
      If ( CaseFlag != cf )
         {
            cf = 0
            Loop, %MaxNameLength%    ; 22: length of longest ahk names
                  CaseCorrectNames%A_Index% = |
            Loop, Parse, SyntaxFiles, |
               {
                  cn := A_LoopField
                  cf := ( cf << 1 ) +  Casecorrect%A_LoopField%
                  If ( Casecorrect%A_LoopField% )
                     {
                        Loop, %MaxNameLength%
                              CaseCorrectNames%A_Index% := CaseCorrectNames%A_Index% . %cn%%A_Index%
                     }
               }
            Loop, %MaxNameLength%
               {
                  Sort CaseCorrectNames%A_Index%, D|
                  ; cni = CaseCorrectNames%A_Index%  / cn := %cni% / msgbox,%cn%
               }
         }
      ahk_MaxNameLength := MaxNameLength
      Return cf
   }

;#############   Create indentation unit depending on options   ###############
CreateIndentationUnits:
   AutoTrim, Off

   ;Create indentation size depending on options
   If Indentation = 1
         IndentUnit = %A_Tab%
   Else
         IndentUnit := N_Chars( NumberSpaces, A_Space )
   ;Create indentation for line continuation
   If IndentCont = 1
         IndentContLine := N_Chars( NumberIndentCont, A_Tab )
   Else
         IndentContLine := N_Chars( NumberIndentCont, A_Space )
   ;set autotrim back to default
   AutoTrim, On
Return

;#############   Indent a Text   ##############################################
IndentText( ByRef Text )
   {
      global
      Now_msec := A_TickCount
      string =
      ;turn off autotrim to handle spaces and tabs
      AutoTrim, Off
      Gosub, ResetStartValues

      Loop, Parse, Text, `n, `r                      ;Read each line
         {
            Line := IndentedLine( A_LoopField )
            String = %String%%Line%`n
            If DebugMode
                  MsgBox, %string%`nIndentLevel: %IndentLevel%`n%indentcommand0%|%indentcommand1%|%indentcommand2%|%indentcommand3%|%indentcommand4%|%indentcommand5%|%indentcommand6%|
         }
      AutoTrim, On
      AdjustFunctionNames( )
      StringTrimRight, Text, String, 1                     ;remove last `n
      String =
   }

;#############   Reset all start values   #####################################
ResetStartValues:
   String =                  ;string to be built up
   Indent =                  ;indentation string
   NextIndent =
   IndentLevel = 0           ;Index of array IndentIncrement and IndentCommand
   InsideBlockComment = 0    ;Status flags
   InsideContinuation = 0
   IndentCommand0 = --
   EmptyLineCount = 0        ;Counters
   TotalLineCount = 0
   CommentLineCount = 0
   CaseCorrectFunctionNames= ;CSV list of function names in current script
   CaseCorrectSubNames=      ;CSV list of subroutine names in current script
   Tfn =
Return

;#############   Set next indentation level and indentation prefix   ##########
SetNextIndentation( Level )
   {
      local n
      NextIndent =
      n = 0
      AutoTrim, Off
      Loop, %Level%      ;Create indentation depending on IndentLevel
         {
            If IndentIncrement%n%
                  NextIndent = %NextIndent%%IndentUnit%
            n++
         }
      AutoTrim, On
      IndentLevel := Level
      Return
   }

SetIndentLevel( Type, Level, Inc )
   {
      local i
      If Type in Sub,Func
            IndentLevel = 0
      i := AtLeast( IndentLevel, 0 ) + 1
      AtLeast( Level,  0 )                   ;in case something went wrong
      If ( IndentLevel = 0 and InStr( Type, "OneLine" ) )
         {
            Type := "-"
            Level = 0
         }
      If Type
            IndentCommand%IndentLevel% := Type
      IndentCommand%i% := "--"            ;necessary mark
      IndentIncrement%IndentLevel% := Inc
      SetNextIndentation( Level )
   }

SetPrevLevel( Type, Level, Offset )
   {
      global
      Loop                            ;Loop backwards through command list
         {
            If Level < 0
                  Break
            If IndentCommand%Level% in %Type%
                  Break
            Level --
         }
      If ( Level < 0 )
            SetNextIndentation( 0 )
      Else
            SetNextIndentation( Level + Offset )
      Return IndentLevel
   }

SetBlockIndentation( Type )
   {
      local IndentBlock
      If PrevCommand in If,Elif,Else,Loop       ;line is a one command block
            SetIndentLevel( "OneLine"PrevCommand, IndentLevel + 1, 1 )
      Else                                  ;normal comand line
            SetPrevLevel( "Sub,LeftBr", IndentLevel, 1 )
      IndentBlock := NextIndent
      SetIndentLevel( Type, IndentLevel + 1, Toralf )
      Return IndentBlock
   }

SetElseBlockIndentation( Type )
   {
      local IndentBlock
      SetPrevLevel( "If,Elif", IndentLevel, 0 )
      IndentBlock := NextIndent
      SetIndentLevel( Type, IndentLevel + 1 , Toralf )
      Return IndentBlock
   }

;#############   Some testing functions   #####################################
IsOneLineIf( Line )
   {            ;eliminate Escaped commas
      local pcomma, pbracket, p
      StringGetPos, p, Line , IfWin
      If p = 0                    ; IfWin... commands are not single line cmds
            Return 0
      StringReplace, Line, Line , ```, , , All
      StringGetPos, pcomma, Line , `,
      If ErrorLevel
            Return 0
      StringGetPos, pbracket, Line , (
      If ( ErrorLevel = 0 and pbracket < pcomma )
            Return 0
      ;Search for a third comma
      StringGetPos, p, Line , `, , L3
      If ErrorLevel = 0              ;Line is possibly a one-line If-statement
            If ( Word3 != "in" and Word3 != "Contains" )
                  Return 1
      Return 0
   }

;#############   Some low level functions   ###################################
N_Chars( n, char )                           ;Concatenate n copies of Char
   {
      ret =
      Loop, %n%
            ret = %ret%%char%
      Return %ret%
   }

AtLeast( ByRef Var, Min )
   {
      If ( Var < Min )
            Var := Min
      Return Var
   }

StringPosNotAlnum( p )
   {
      global String
      StringMid, a, String, p, 1
      If a is Alnum
            Return 0
      If a = _
            Return 0
      Return 1
   }

NotAlnum( ByRef String, p )
   {
      StringMid, a, String, p, 1
      If a is Alnum
            Return 0
      If a = _
            Return 0
      Return 1
   }

;#############   SplitLine   ##################################################
SplitLine( ByRef Line )
   {
      local p, TempLine
      Word1 =
      Word2 =
      StringReplace, TempLine, Line, %A_Tab%, %A_Space%, All
      StringGetPos, p, TempLine, `;
      If ( p >= 0 )
            StringLeft, TempLine, TempLine, p + 1
      StringReplace, TempLine, TempLine, `, , %A_Space%, All
      StringReplace, TempLine, TempLine, %A_Space%%A_Space%%A_Space%%A_Space%, %A_Space%, All
      StringReplace, TempLine, TempLine, %A_Space%%A_Space%%A_Space%, %A_Space%, All
      StringReplace, TempLine, TempLine, %A_Space%%A_Space%, %A_Space%, All
      StringSplit, Word, TempLine, %A_Space%%A_Tab%`,
   }

;#############   Construct an indented line   #################################
IndentedLine( OriginalLine )
   {
      local Line, PrevIndex

      Toralf := Style = 2
      ;set indentation to the amount determined by previous lines
      Indent := NextIndent
      PrevIndex := IndentLevel - 1
      AtLeast( PrevIndex, 0 )

      AutoTrim, On
      ;count line
      TotalLineCount ++
      ;trim the line  -  does not work with Line := OriginalLine
      Line = %OriginalLine%

      ;get first character of line
      StringLeft, FirstChar, Line, 1
      StringLeft, FirstTwoChars, Line , 2

      If FirstChar =                          ;line is empty
         {
            EmptyLineCount ++
            Return
         }

      SplitLine( Line )
      FirstWord := Word1
      SecondWord := Word2

      ;function implementation?
      If ( FirstChar != BlockBegin
                 and FirstChar != CommentChar
                 and IndentLevel = 1 )   ;line is not start of bracket block
            If tfn
               {
                  ;if an earlier line begins with a function name,
                  ;  then that line is not the beginning of the function implementation
                  tfn =      ;dismiss the function name stored
                  SetNextIndentation( 0 )
               }

      StringGetPos, BracketPos, FirstWord, (
      FirstWordIsFunctionDef := ( IndentLevel = 0 and BracketPos > 0 )
      If FirstWordIsFunctionDef
         {
            Tfn := TidyFunctionName( FirstWord, BracketPos )
            FirstWordIsFunctionDef := tfn <> ""
         }

      ;check: is line a continuation of the previous line?
      LineIsImplicitCont := ( FirstChar = ", "
              or FirstTwoChars = "||"
              or FirstTwoChars = "&&"
              or FirstWord = "and"
              or FirstWord = "or" )

      ;get last character of First word
      StringRight, FirstWordLastChar, FirstWord, 1

      AutoTrim, Off

      ;###### after all the preparations, here the work begins ##########
      If ( FirstChar = "#" )                        ;line is a directive
            Loop, Parse, ListOfDirectives, CSV
                  If ( FirstWord = A_LoopField )
                     {
                        StringReplace, Line, Line, %A_LoopField%, %A_LoopField%
                        Return %Line%
                     }

      If ( FirstTwoChars = BlockCommentEnd )    ;line is end of BlockComment
         {
            InsideBlockComment := False
            CommentLineCount ++
            Return %Line%
         }

      If InsideBlockComment               ;line is inside a BlockComment
         {
            CommentLineCount ++
            If KeepBlockCommentIndent
                  Return %OriginalLine%
            Else
                  Return %Line%
         }

      If ( FirstTwoChars = BlockCommentBegin )     ;line is start of a BlockComment
         {
            InsideBlockComment := True
            CommentLineCount ++
            Return %Line%
         }

      If ( FirstWord = ContBlockBegin )        ;line is start of a continuation block
         {
            InsideContinuation ++                  ;allow nested cont´s
            Return Indent Line
         }
      If ( FirstWord = ContBlockEnd and InsideContinuation ) ;end of a continuation block
         {
            InsideContinuation --
            AtLeast( InsideContinuation, 0 )
            Return Indent Line
         }

      If ( InsideContinuation )                 ; don´t indent
            If KeepContIndent
                  Return %OriginalLine%
            Else
                  Return %Line%

      If ( FirstChar = ":" )                  ;line is hotstring
         {
            SetIndentLevel( "Sub", 1, Toralf )
            Return %Line%
         }

      If ( FirstChar = BlockBegin )            ;line is start of bracket block
         {
            If ( IndentLevel = 1 and  tfn <> "" )   ; start of a function implementation
                  If tfn not in %CaseCorrectFunctionNames%   ; build a CSV list
                        CaseCorrectFunctionNames = %CaseCorrectFunctionNames%,%tfn%
            tfn =
            SetIndentLevel( "LeftBr", IndentLevel + 1, 1 )
            Return Indent Line
         }

      If ( FirstChar = BlockEnd )               ;line is end of bracket block
         {
            SetPrevLevel( "LeftBr", IndentLevel, -1 )
            If Toralf
                  Return NextIndent IndentUnit Line
            Else
                  Return NextIndent Line
         }

      PrevCommand := IndentCommand%PrevIndex%

      If ( FirstChar = CommentChar )           ;line is comment
         {
            CommentLineCount ++
            If ( InStr( PrevCommand, "OneLine" ) )
                  SetPrevLevel( "Sub,LeftBr", IndentLevel, 1 )
            Return NextIndent Line
         }

      If ( FirstWordLastChar = ":" )    ;line is start of subroutine or Hotkey
            IfNotInString , FirstWord, `:`:     ;line is start of a subroutine
               {
                  StringLeft, Tsn, Line, StrLen( FirstWord ) - 1
                  If Tsn not in %CaseCorrectSubNames%        ; build a CSV list
                        CaseCorrectSubNames = %CaseCorrectSubNames%,%Tsn%
                  SetIndentLevel( "Sub", 1, Toralf )
                  SetKeyWordCase( Line )
                  Return %Line%
               }

      SetKeyWordCase( Line )

      IfInString , FirstWord, `:`:    ;line is a hotkey or hotstring definition
         {
            If ( SecondWord <> "" and Asc( SecondWord ) != 59 )
                  SetIndentLevel( "Sub", 0 , 0 )     ; one line hotkey def´n
            Else
                  SetIndentLevel( "Sub", 1, Toralf )  ;probably multiline def´n
            Return %Line%
         }

      If FirstWordIsFunctionDef               ;line is function
         {
            SetIndentLevel( "Func", 1, Toralf )
            Return %Line%
         }

      If ( FirstWord = "Loop" )              ;line is start of Loop block
            Return  SetBlockIndentation( "Loop" ) line

      If FirstWord in %ListOfIFCommands%   ;line is start of If-Statement
         {
            StringReplace, Line, Line, if, If
            If ( IsOneLineIf( Line ) )     ;Line is a one-line If-statement
                  Return SetBlockIndentation( "1If" ) Line
            Else
                  Return SetBlockIndentation( "If" ) Line
         }

      If ( FirstWord = "Else" )                    ;line begins an Else block
            If SecondWord in %ListOfIfCommands%   ;Else If ...
                  Return SetElseBlockIndentation( "Elif" ) Line
            Else                                  ;just a plain Else
                  Return SetElseBlockIndentation( "Else" ) Line

      ;If line is a continuation add the appropiate indentation
      If LineIsImplicitCont
            Return Indent IndentContLine Line

      Else                          ;line is a normal command or Return
         {
            If ( FirstWord = "Return" and IndentCommand0 = "Sub" )
               {
                  If PrevCommand in If,Elif,Else,Loop
                        SetIndentLevel( "OneLine"PrevCommand, IndentLevel + 1, 1 )
                  Else
                        If ( SetPrevLevel( "Sub,LeftBr", IndentLevel, 1 ) = 1 )
                              SetIndentLevel( "0", 0 , 0 )
               }
            Else
                  If PrevCommand in If,Elif,Else,Loop
                        SetIndentLevel( "OneLine"PrevCommand, IndentLevel + 1, 1 )
                  Else If PrevCommand in Func      ;Line follows a function call
                        SetIndentLevel( "0", 0, 0 )
                  Else                             ;line is normal command
                        SetPrevLevel( "Sub,LeftBr", IndentLevel, 1 )
            Return NextIndent Line
         }
   }

;#############   Show debug MsgBox ############################################
/*
ShowDebugStrings:
   msgtext = line#: %TotalLineCount%`n
   msgtext = %msgtext%Style: %Style%`n
   msgtext = %msgtext%line: %Line%`n
   msgtext = %msgtext%Indent: |%Indent%|`n
   msgtext = %msgtext%1stChar: >%FirstChar%<`n
   msgtext = %msgtext%1st Word: >%FirstWord%<`n
   msgtext = %msgtext%2nd Word: >%SecondWord%<`n
   msgtext = %msgtext%1st WordLastChar: >%FirstWordLastChar%<`n`n
   msgtext = %msgtext%IndentLevel: %IndentLevel%`n
   msgtext = %msgtext%Indent1: %IndentIncrement1% - %IndentCommand1%`n
   msgtext = %msgtext%Indent2: %IndentIncrement2% - %IndentCommand2%`n
   msgtext = %msgtext%Indent3: %IndentIncrement3% - %IndentCommand3%`n
   msgtext = %msgtext%Indent4: %IndentIncrement4% - %IndentCommand4%`n
   msgtext = %msgtext%Indent5: %IndentIncrement5% - %IndentCommand5%`n
   msgtext = %msgtext%Indent6: %IndentIncrement6% - %IndentCommand6%`n
   msgtext = %msgtext%Indent7: %IndentIncrement7% - %IndentCommand7%`n
   msgtext = %msgtext%Indent8: %IndentIncrement8% - %IndentCommand8%`n
   msgtext = %msgtext%Indent9: %IndentIncrement9% - %IndentCommand9%`n
   msgtext = %msgtext%Indent10: %IndentIncrement10% - %IndentCommand10%`n
   msgtext = %msgtext%Indent11: %IndentIncrement11% - %IndentCommand11%`n
   msgtext = %msgtext%`nDirectives: %ListOfDirectives%`n
   msgtext = %msgtext%`nIf-Commands: %ListOfIFCommands%`n
   msgtext = %msgtext%`nCommandNames: %CommandNames%`n
   msgtext = %msgtext%`nKeywords: %Keywords%`n
   msgtext = %msgtext%`nKeys: %Keys%`n
   msgtext = %msgtext%`nVariables: %Variables%`n
   MsgBox %msgtext%`n%String%
Return
*/
;#############   Case correction of line   ####################################
SetKeyWordCase( ByRef String )
   ; identify sequences of alphanumeric characters (i. e. words)
   ; compare them with list of keywords and if found replace them
   {
      local Ls, Ls2, Line, inquote, p1, wl
      ;p1: pos of 1st char of a word, wl: word length, inquote: flag
      Ls := StrLen( String )
      StringGetPos, Ls2, String, %CommentChar%
      If ErrorLevel
            Ls2 := Ls
      StringLeft, Line, String, %Ls2%
      p1 = 1
      inquote = 0
      Loop, Parse, Line,                         ; find words
         {
            If inquote
                  If A_LoopField = "
                     {
                        inquote = 0
                        p1 = 0
                     }
                  Else
                        Continue
            Else
                  If A_LoopField= "          ; skip quoted text
                        inquote = 1

            If A_LoopField is Alnum
                  If p1
                        wl ++
                  Else
                     {
                        p1 := A_Index      ; start of a new word
                        wl = 1
                     }
            Else if A_LoopField = _
                  If p1
                        wl ++
                  Else
                     {
                        p1 := A_Index      ; start of a new word
                        wl = 1
                     }
            Else                           ; no alnum char
                  If ( p1 )                ; end of word found
                     {
                        If ( wl >= 3 and wl <= ahk_MaxNameLength )
                              TestReplace_ahkName( String, LS, p1, wl )
                        p1 = 0
                     }
                  Else
                        Continue
         }
      If ( p1 and wl >= 3 and wl <= ahk_MaxNameLength )  ; end of line
            TestReplace_ahkName( String, Ls, p1, wl )
   }

TestReplace_ahkName( ByRef String, Ls, p1, wl )
   {  ; wl: word length
      local cn, w, p2, Name
      StringMid, w, String, p1 , wl
      cn = CaseCorrectNames%wl%
      StringGetPos, p2, %cn%, |%w%
      If ErrorLevel
            Return
      StringMid, Name, %cn%, p2 + 2 , wl

      ReplaceName( String, Name, p1 - 1, Ls - p1 - wl +1 )
   }

;#############   Tidy up Function and Subroutine Names   ######################
TidyFunctionName( Word, Bpos )
   {
      local a, n, tfn
      n := Bpos
      Loop
         {
            StringMid, a, word, n, 1
            If ( a <> "_" )
                  If a is not Alnum
                        Break
            n--
            If n = 0
                  Break
         }
      If n = 0
            StringMid, tfn, Word, 1, Bpos+1
      Return tfn
   }

AdjustFunctionNames( )
   {
      local n, a, p, ls, ln, tn   ; tn: tidy name, ln: name length
      ls := StrLen( String )
      If ( CaseCorrectFunctions )
            CaseCorrectFunctionNames = %CaseCorrectFunctionNames%%ahk_functions%
      ; MsgBox,%CaseCorrectFunctionNames%
      Loop, Parse, CaseCorrectFunctionNames, CSV
         {
            If A_Index = 1
                  Continue
            tn := A_LoopField
            ln := StrLen( tn )
            p = 0
            Loop
               {
                  n := p + 1
                  StringGetPos, p, String, %tn%, , n
                  IfLess, p, 0, Break

                  If StringPosNotAlnum( p )
                        ReplaceName( string, tn, p, ls - p - ln )
               }
         }
      Loop, Parse, CaseCorrectSubNames, CSV
         {
            If A_Index = 1
                  Continue
            tn := A_LoopField
            ln := StrLen( tn )
            p = 0
            Loop
               {
                  n := p + 1
                  StringGetPos, p, String, %tn%, , n
                  IfLess, p, 1, Break
                  StringMid, a, String, p, 1
                  If a is Alnum
                        If ( a = "g" )
                           {
                              TestAndReplaceSubName( string, tn, "Gui, ", ls, ln, p )
                              TestAndReplaceSubName( string, tn, "Gui ", ls, ln, p )
                           }
                        Else
                              Continue
                  TestAndReplaceSubName( string, tn, "Gosub", ls, ln, p )
                  TestAndReplaceSubName( string, tn, "Menu", ls, ln, p )
                  TestAndReplaceSubName( string, tn, "`:`:", ls, ln, p )
                  TestAndReplaceSubName( string, tn, "Hotkey", ls, ln, p )
               }
         }
   }

TestAndReplaceSubName( ByRef string, ByRef name, test, ls, ln, p )
   {
      local pn, pt
      StringGetPos, pt, String, %test%, R , ls - p
      StringGetPos, pn, String, `n, R , ls - p
      If ( pn < pt )                   ;string %test% in the same line
            ReplaceName( string, name, p, ls - p - ln )
   }

ReplaceName( ByRef string, ByRef name, pl, pr )
   {
      ; pl: left part, pr: right part to remain
      local StrL, StrR
      StringLeft, StrL, String, pl
      StringRight, StrR, String, pr
      String = %StrL%%name%%StrR%
   }

;#############   On Gui close exit all   ######################################
GuiClose:
   ;store current position and settings and exit app
   WinGetPos, PosX, PosY, SizeW, SizeH, %ScriptName%
   Gui, Submit
   IniWrite, x%PosX%, %ScriptName%.ini, General, PosX_Gui
   IniWrite, y%PosY%, %ScriptName%.ini, General, PosY_Gui
   IniWrite, %Extension%, %ScriptName%.ini, Settings, Extension
   IniWrite, %Indentation%, %ScriptName%.ini, Settings, Indentation
   IniWrite, %NumberSpaces%, %ScriptName%.ini, Settings, NumberSpaces
   IniWrite, %NumberIndentCont%, %ScriptName%.ini, Settings, NumberIndentCont
   IniWrite, %Style%, %ScriptName%.ini, Settings, Style
   IniWrite, %CaseCorrectCommandNames%, %ScriptName%.ini, Settings, CaseCorrectCommandNames
   IniWrite, %CaseCorrectVariables%, %ScriptName%.ini, Settings, CaseCorrectVariables
   IniWrite, %CaseCorrectKeys%, %ScriptName%.ini, Settings, CaseCorrectKeys
   IniWrite, %CaseCorrectKeywords%, %ScriptName%.ini, Settings, CaseCorrectKeywords
   IniWrite, %CaseCorrectFunctions%, %ScriptName%.ini, Settings, CaseCorrectFunctions
   IniWrite, %statistics%, %ScriptName%.ini, Settings, statistics
   IniWrite, %KeepContIndent%, %ScriptName%.ini, Settings, KeepContIndent
   IniWrite, %KeepBlockCommentIndent%, %ScriptName%.ini, Settings, KeepBlockCommentIndent
   ExitApp
Return
;#############   End of File   #################################################
Hajos

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
It looks very powerful. Thanks for all the improvements.

Rajat
  • Members
  • 1904 posts
  • Last active: Jul 17 2015 07:45 AM
  • Joined: 28 Mar 2004
going great guns!!

MIA

CleanNews.in : Bite sized latest news headlines from India with zero bloat


AgentSmith15
  • Members
  • 37 posts
  • Last active: Jan 05 2009 07:52 AM
  • Joined: 06 May 2005
Hmm I get this error?

---------------------------
Auto-Syntax-Tidy v6.1.ahk
---------------------------
Error at line 585.

Line Text: ( FirstChar != BlockBegin
Error: Missing ")"

Dewi Morgan
  • Members
  • 191 posts
  • Last active: Jun 07 2015 04:02 AM
  • Joined: 03 Oct 2005
From the sounds of it you're running a version of ahk from before v1.0.35.03, which does not allow if () expressions to be split over multiple lines. Upgrading should cause this to work better :)
Yet another hotkeyer.