/****************************** Module Header ******************************* * * Module Name: tabsspaces.e * * Copyright (c) Netlabs EPM Distribution Project 2004 * * $Id$ * * =========================================================================== * * This file is part of the Netlabs EPM Distribution package and is free * software. You can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * Netlabs EPM Distribution. This library is distributed in the hope that it * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * ****************************************************************************/ ; --------------------------------------------------------------------------- defc Spaces2Tabs, TabCompress parse arg arg1 . PrevTabs = .tabs if arg1 = '' | not IsNum( arg1) then 'CommandLine TabCompress 'word( .tabs, 1) return else if .tabs <> arg1 then -- Ask once per file for to set tabs permanently getfileid fid AskedForTabs = GetAVar( fid'.askedfortabs') if AskedForTabs = '' then Title = 'Change tabs for this file' Text = 'The tabs value for this file is about to change.'\n\n Text = Text || 'Press "OK" to make it permanent, otherwise "Cancel":' Style = MB_OKCANCEL + MB_ICONQUESTION + MB_DEFBUTTON1 + MB_MOVEABLE rcx = WinMessageBox( Title, Text, Style) if rcx = MBID_OK then 'Tabs 'arg1 else 'Tabs NOEA 'arg1 endif elseif AskedForTabs = 1 then 'Tabs 'arg1 else 'Tabs NOEA 'arg1 endif SetAVar( fid'.askedfortabs', (rcx = MBID_OK)) endif TabWidth = arg1 endif KeyPath = '\NEPMD\User\TabsSpaces\Compress\IndentOnly' fIndentOnly = (QueryConfigKey( KeyPath) <> 0) fFileIsMarked = FileIsMarked() if fFileIsMarked then getmark markfirstline, marklastline, markfirstcol, marklastcol, markfid -- Handle char mark and lastcol = 0 if marklastcol = 0 then marklastline = marklastline - 1 marklastcol = MAXCOL endif FirstLine = markfirstline LastLine = marklastline else FirstLine = 1 LastLine = .last endif PrevTabWidth = '' NextAttrLine = 0 fSearchAttr = 1 --cSearch = 0 --cFast = 0 --cSlow = 0 call NextCmdAltersText() do Line = FirstLine to LastLine LineStr = textline( Line) fTabFound = (pos( \9, Linestr) <> 0) -- Don't try to expand it when no tabs are found if fTabFound then if PrevTabWidth = '' then -- Ask for previous tab width Title = 'Expand tabs before compress' Text = 'Previous tabs value:' -- Set width of EntryBox: Text = Text''copies( ' ', max( 100 - length( Text), 0)) Buttons = '/'OK__MSG'/'CANCEL__MSG Entry = word( PrevTabs, 1) parse value EntryBox( Title, Buttons, Entry, 0, 240, atoi( 1) || atoi( 0) || atol( 0) || Text) with Button 2 Val \0 Val = strip( Val) if Button = \1 then -- OK PrevTabWidth = Val else -- Cancel PrevTabWidth = Entry endif endif -- Expand with the previous tab width -- Note: Expand the whole line. rcx = TabExpandLine( Line, PrevTabWidth) -- Note: After expansion, markfirstcol and marklastcol may have changed. endif StartCol = 1 EndCol = MAXCOL if fFileIsMarked then if Line = FirstLine then StartCol = markfirstcol endif if Line = LastLine then EndCol = marklastcol endif endif -- Determine if search for attributes is required if NextAttrLine = -1 then fSearchAttr = 0 else if Line > NextAttrLine then fSearchAttr = 1 else fSearchAttr = 0 endif endif if fSearchAttr then -- Search next attribute from this line on FoundClass = ANY_CLASS -- 0 FoundOffst = -300 FoundCol = 1 FoundLine = Line attribute_action 1, FoundClass, FoundOffst, FoundCol, FoundLine -- 1 = FIND NEXT ATTR if FoundClass = 0 then NextAttrLine = -1 else NextAttrLine = FoundLine endif --cSearch = cSearch + 1 --dprintf( rightstr( Line, 3)': Searched for next attr: NextAttrLine = 'NextAttrLine) endif -- Determine if slower procs must be used fUseFastProc = 0 do once = 1 to 1 if Line >= NextAttrLine & NextAttrLine <> -1 then -- Attributes found leave endif if Line = .line then -- Restore cursor leave endif if StartCol <> 1 then -- Line = markfirstline leave endif if EndCol <> MAXCOL then -- Line = marklastline leave endif fUseFastProc = 1 enddo if fUseFastProc then -- Fast procs, remove attributes fChangedX = 0 if fTabFound then -- Expand line first NewLineStr = TabExpandStr( LineStr, PrevTabWidth, fChangedX) if fChangedX then LineStr = NewLineStr endif endif fChanged = 0 -- Compress line NewLineStr = TabCompressStr( LineStr, TabWidth, fChanged, fIndentOnly) if fChanged | fChangedX then replaceline NewLineStr, Line endif --cFast = cFast + 1 else -- Slow procs, preserve attributes if fTabFound then -- Expand whole line first rcx = TabExpandLine( Line, PrevTabWidth) endif -- Compress line rcx = TabCompressLine( Line, TabWidth, fIndentOnly, '', StartCol, EndCol) --cSlow = cSlow + 1 endif enddo --dprintf( 'cSearch = 'cSearch', cFast = 'cFast', cSlow = 'cSlow) ; --------------------------------------------------------------------------- defc TabCompressAll parse arg TabWidth . if TabWidth = '' | not IsNum( TabWidth) then TabWidth = word( .tabs, 1) endif KeyPath = '\NEPMD\User\TabsSpaces\Compress\IndentOnly' fIndentOnly = (QueryConfigKey( KeyPath) <> 0) PrevTabWidth = TabWidth FirstLine = 1 LastLine = .last NextAttrLine = 0 fSearchAttr = 1 --cSearch = 0 --cFast = 0 --cSlow = 0 call NextCmdAltersText() do Line = FirstLine to LastLine LineStr = textline( Line) fTabFound = (pos( \9, Linestr) <> 0) -- Determine if search for attributes is required if NextAttrLine = -1 then fSearchAttr = 0 else if Line > NextAttrLine then fSearchAttr = 1 else fSearchAttr = 0 endif endif if fSearchAttr then -- Search next attribute from this line on FoundClass = ANY_CLASS -- 0 FoundOffst = -300 FoundCol = 1 FoundLine = Line attribute_action 1, FoundClass, FoundOffst, FoundCol, FoundLine -- 1 = FIND NEXT ATTR if FoundClass = 0 then NextAttrLine = -1 else NextAttrLine = FoundLine endif --cSearch = cSearch + 1 --dprintf( rightstr( Line, 3)': Searched for next attr: NextAttrLine = 'NextAttrLine) endif -- Determine if slower procs must be used fUseFastProc = 0 do once = 1 to 1 if Line >= NextAttrLine & NextAttrLine <> -1 then -- Attributes found leave endif if Line = .line then -- Restore cursor leave endif fUseFastProc = 1 enddo if fUseFastProc then -- Fast procs, remove attributes fChangedX = 0 if fTabFound then -- Expand line first NewLineStr = TabExpandStr( LineStr, PrevTabWidth, fChangedX) if fChangedX then LineStr = NewLineStr endif endif fChanged = 0 -- Compress line NewLineStr = TabCompressStr( LineStr, TabWidth, fChanged, fIndentOnly) if fChanged | fChangedX then replaceline NewLineStr, Line endif --cFast = cFast + 1 else -- Slow procs, preserve attributes if fTabFound then -- Expand whole line first rcx = TabExpandLine( Line, PrevTabWidth) endif -- Compress line rcx = TabCompressLine( Line, TabWidth, fIndentOnly) --cSlow = cSlow + 1 endif enddo --dprintf( 'cSearch = 'cSearch', cFast = 'cFast', cSlow = 'cSlow) ; --------------------------------------------------------------------------- defc Tabs2Spaces, TabExpand parse arg arg1 . if arg1 = '' | not IsNum( arg1) then 'CommandLine TabExpand 'word( .tabs, 1) return else if .tabs <> arg1 then -- Ask once per file for to set tabs permanently getfileid fid AskedForTabs = GetAVar( fid'.askedfortabs') if AskedForTabs = '' then Title = 'Change tabs for this file' Text = 'The tabs value for this file is about to change.'\n\n Text = Text || 'Press "OK" to make it permanent, otherwise "Cancel":' Style = MB_OKCANCEL + MB_ICONQUESTION + MB_DEFBUTTON1 + MB_MOVEABLE rcx = WinMessageBox( Title, Text, Style) if rcx = MBID_OK then 'Tabs 'arg1 else 'Tabs NOEA 'arg1 endif elseif AskedForTabs = 1 then 'Tabs 'arg1 else 'Tabs NOEA 'arg1 endif SetAVar( fid'.askedfortabs', (rcx = MBID_OK)) endif TabWidth = arg1 endif fFileIsMarked = FileIsMarked() if fFileIsMarked then getmark markfirstline, marklastline, markfirstcol, marklastcol, markfid -- Handle char mark and lastcol = 0 if marklastcol = 0 then marklastline = marklastline - 1 marklastcol = MAXCOL endif FirstLine = markfirstline LastLine = marklastline else FirstLine = 1 LastLine = .last endif PrevTabWidth = '' NextAttrLine = 0 fSearchAttr = 1 --cSearch = 0 --cFast = 0 --cSlow = 0 call NextCmdAltersText() do Line = FirstLine to LastLine LineStr = textline( Line) StartCol = 1 EndCol = MAXCOL if fFileIsMarked then if Line = FirstLine then StartCol = markfirstcol endif if Line = LastLine then EndCol = marklastcol endif endif -- Determine if search for attributes is required if NextAttrLine = -1 then fSearchAttr = 0 else if Line > NextAttrLine then fSearchAttr = 1 else fSearchAttr = 0 endif endif if fSearchAttr then -- Search next attribute from this line on FoundClass = ANY_CLASS -- 0 FoundOffst = -300 FoundCol = 1 FoundLine = Line attribute_action 1, FoundClass, FoundOffst, FoundCol, FoundLine -- 1 = FIND NEXT ATTR if FoundClass = 0 then NextAttrLine = -1 else NextAttrLine = FoundLine endif --cSearch = cSearch + 1 --dprintf( rightstr( Line, 3)': Searched for next attr: NextAttrLine = 'NextAttrLine) endif -- Determine if slower proc must be used fUseFastProc = 0 do once = 1 to 1 if Line >= NextAttrLine & NextAttrLine <> -1 then -- Attributes found leave endif if Line = .line then -- Restore cursor leave endif if StartCol <> 1 then -- Line = markfirstline leave endif if EndCol <> MAXCOL then -- Line = marklastline leave endif fUseFastProc = 1 enddo if fUseFastProc then -- Fast proc, removes attributes fChanged = 0 -- Expand line NewLineStr = TabExpandStr( LineStr, TabWidth, fChanged) if fChanged then replaceline NewLineStr, Line endif --cFast = cFast + 1 else -- Slow proc, preserves attributes -- Expand line rcx = TabExpandLine( Line, TabWidth) --cSlow = cSlow + 1 endif enddo --dprintf( 'cSearch = 'cSearch', cFast = 'cFast', cSlow = 'cSlow) ; --------------------------------------------------------------------------- defc TabExpandAll parse arg TabWidth . if TabWidth = '' | not IsNum( TabWidth) then TabWidth = word( .tabs, 1) endif FirstLine = 1 LastLine = .last NextAttrLine = 0 fSearchAttr = 1 --cSearch = 0 --cFast = 0 --cSlow = 0 call NextCmdAltersText() do Line = FirstLine to LastLine LineStr = textline( Line) -- Determine if search for attributes is required if NextAttrLine = -1 then fSearchAttr = 0 else if Line > NextAttrLine then fSearchAttr = 1 else fSearchAttr = 0 endif endif if fSearchAttr then -- Search next attribute from this line on FoundClass = ANY_CLASS -- 0 FoundOffst = -300 FoundCol = 1 FoundLine = Line attribute_action 1, FoundClass, FoundOffst, FoundCol, FoundLine -- 1 = FIND NEXT ATTR if FoundClass = 0 then NextAttrLine = -1 else NextAttrLine = FoundLine endif --cSearch = cSearch + 1 --dprintf( rightstr( Line, 3)': Searched for next attr: NextAttrLine = 'NextAttrLine) endif -- Determine if slower proc must be used fUseFastProc = 0 do once = 1 to 1 if Line >= NextAttrLine & NextAttrLine <> -1 then -- Attributes found leave endif if Line = .line then -- Restore cursor leave endif fUseFastProc = 1 enddo if fUseFastProc then -- Fast proc, removes attributes fChanged = 0 -- Expand line NewLineStr = TabExpandStr( LineStr, TabWidth, fChanged) if fChanged then replaceline NewLineStr, Line endif --cFast = cFast + 1 else -- Slow proc, preserves attributes -- Expand line rcx = TabExpandLine( Line, TabWidth) --cSlow = cSlow + 1 endif enddo --dprintf( 'cSearch = 'cSearch', cFast = 'cFast', cSlow = 'cSlow) ; --------------------------------------------------------------------------- ; Avoid tab chars in quoted strings, if quote starts in this line. defproc TabCompressStr( LineStr, TabWidth, var fChanged) -- TabCompressStr fIndentOnly = arg( 4) if wordpos( arg( 4), '0 1') = 0 then fIndentOnly = 0 endif fChanged = 0 TabChar = \9 rest = LineStr TmpLineStr = '' Col = 1 if fIndentOnly then pNonBlank = max( 1, verify( rest, ' '\t)) endif do forever p = pos( ' ', rest) if p = 0 then leave endif if fIndentOnly then -- Check pos > indent if Col + p >= pNonBlank then leave endif endif LeftPart = substr( rest, 1, p - 1) RightPart = substr( rest, p) -- including all spaces TmpLineStr = TmpLineStr''LeftPart Col = Col + length( LeftPart) SpaceLen = max( 0, verify( RightPart, ' ', 'N') - 1) -- Don't process spaces at line end if SpaceLen = 0 then leave endif rest = substr( rest, p + SpaceLen) -- stripped leading spaces -- Don't process enquoted string if IsLiteral( TmpLineStr''RightPart, Col) then -- TmpLineStr is here only left part before current doublespace TmpLineStr = TmpLineStr''copies( ' ', SpaceLen) Col = Col + SpaceLen SpaceLen = 0 endif -- Convert spaces do while SpaceLen > 0 NextTabCol = Col + TabWidth - ((Col - 1) // TabWidth) --NextTabCol = (((Col - 1) % TabWidth) + 1) * TabWidth + 1 -- works as well if (NextTabCol > Col) & (Col + SpaceLen >= NextTabCol) then TmpLineStr = TmpLineStr''TabChar SpaceLen = SpaceLen - (NextTabCol - Col) Col = NextTabCol fChanged = 1 else TmpLineStr = TmpLineStr''copies( ' ', SpaceLen) Col = Col + SpaceLen SpaceLen = 0 endif enddo enddo TmpLineStr = TmpLineStr''rest return TmpLineStr ; --------------------------------------------------------------------------- ; Preserves attributes. ; If StartCol is specified and <> 1, then it must be on a tab column, e.g. 7 ; for TabWidth = 3. Otherwise ExpCol can't be calculated correctly. defproc TabCompressLine( Line, TabWidth) fIndentOnly = arg( 3) fRestoreCol = arg( 4) StartCol = arg( 5) EndCol = arg( 6) if not wordpos( fIndentOnly, '0 1') then fIndentOnly = 0 endif if not wordpos( fRestoreCol, '0 1') then fRestoreCol = 1 endif if Line <> .line then fRestoreCol = 0 endif if StartCol = '' then StartCol = 1 endif if EndCol = '' then EndCol = -1 -- -1 means: search until end of line endif rcx = 1 AddCol = 0 TwoSpc = ' ' TabChar = \9 TabLen = 1 psave_pos( savepos) getsearch savesearch LineStr = textline( Line) if fIndentOnly then pNonBlank = max( 1, verify( LineStr, ' '\t)) endif -- When fRestoreCol is 1, the line is split at the cursor into -- LeftLineStr and RightLineStr. These parts are separately processed. if fRestoreCol then Maxn = 2 else Maxn = 1 endif do n = 1 to Maxn if fRestoreCol then -- means: Line = .line -- Cursor is on this line. Split line at cursor. if n = 1 then -- First part ThisStartCol = StartCol ThisEndCol = .col - 1 else -- Second part ThisStartCol = ThisEndCol + 1 ThisEndCol = EndCol endif else -- Cursor not on this line or fRestoreCol deactivated. ThisStartCol = StartCol ThisEndCol = EndCol endif .col = ThisStartCol .lineg = line ExpCol = .col do forever PrevCol = .col display -14 -- Search 'xcom l '\1''TwoSpc display 14 -- Check rc lrc = rc if lrc then leave endif -- Check pos. if .line <> Line then leave endif if ThisEndCol > -1 then if .col > ThisEndCol then leave endif endif -- The search adanced .col. Advance ExpCol as well. DeltaCol = .col - PrevCol ExpCol = ExpCol + DeltaCol -- Check pos > indent if fIndentOnly then if ExpCol >= pNonBlank then leave endif endif LineStr = textline( .line) LeftLineStr = leftstr( LineStr, .col - 1) RightLineStr = substr( LineStr, .col) -- Don't process enquoted string if IsLiteral( LeftLineStr''RightLineStr, .col) then .col = .col + length( TwoSpc) iterate endif SpaceLen = max( 0, verify( RightLineStr, ' ', 'N') - 1) -- Don't process spaces at line end if SpaceLen = 0 then leave endif -- Calc NextTabCol from current expanded col on ExpNextTabCol = ExpCol + TabWidth - ((ExpCol - 1) // TabWidth) --ExpNextTabCol = (((ExpCol - 1) % TabWidth) + 1) * TabWidth + 1 -- works as well -- Convert ExpNextTabCol to NextTabCol NextTabCol = ExpNextTabCol - (ExpCol - .col) -- SpaceLen must be enough for one full tabwidth if .col + SpaceLen < NextTabCol then leave endif NextSpaceLen = NextTabCol - .col NextSpace = copies( ' ', NextSpaceLen) display -14 -- Replace 'xcom c '\1''NextSpace''\1''TabChar display 14 -- Check rc crc = rc if crc then leave endif rcx = 0 -- line changed -- Move cursor after replace, adapt ThisEndCol, EndCol, pNonBlank and ExpCol .col = .col + TabLen if n = 1 then AddCol = AddCol - NextSpaceLen + TabLen endif if ThisEndCol > -1 then ThisEndCol = ThisEndCol - NextSpaceLen + TabLen endif if EndCol > -1 then EndCol = EndCol - NextSpaceLen + TabLen endif ExpCol = ExpCol + NextSpaceLen -- Check pos. if ThisEndCol > -1 then if .col > ThisEndCol then leave endif endif enddo enddo setsearch savesearch prestore_pos( savepos) -- Restore col if fRestoreCol then .col = .col + AddCol endif return rcx ; --------------------------------------------------------------------------- defproc TabExpandStr( LineStr, TabWidth, var fChanged) fChanged = 0 TabChar = \9 if pos( TabChar, LineStr) = 0 then return LineStr endif rest = LineStr TmpLineStr = '' do forever p = pos( TabChar, rest) if p = 0 then leave endif LeftPart = substr( rest, 1, p - 1) TmpLineStr = TmpLineStr''LeftPart rest = substr( rest, p + 1) Col = length( TmpLineStr) + 1 -- processed columns before current tab char NextTabCol = Col + TabWidth - ((Col - 1) // TabWidth) --NextTabCol = (((Col - 1) % TabWidth) + 1) * TabWidth + 1 -- works as well SpaceLen = NextTabCol - Col TmpLineStr = TmpLineStr''copies( ' ', SpaceLen) fChanged = 1 enddo TmpLineStr = TmpLineStr''rest return TmpLineStr ; --------------------------------------------------------------------------- ; Preserves attributes. defproc TabExpandLine( Line, TabWidth) fRestoreCol = arg( 3) StartCol = arg( 4) EndCol = arg( 5) if not wordpos( fRestoreCol, '0 1') then fRestoreCol = 1 endif if Line <> .line then fRestoreCol = 0 endif if StartCol = '' then StartCol = 1 endif if EndCol = '' then EndCol = -1 endif rcx = 1 AddCol = 0 TabChar = \9 TabLen = 1 psave_pos( savepos) getsearch savesearch -- When fRestoreCol is 1, the line is split at the cursor into -- LeftLineStr and RightLineStr. These parts are separately processed. if fRestoreCol then Maxn = 2 else Maxn = 1 endif do n = 1 to Maxn if fRestoreCol then -- means: Line = .line -- Cursor is on this line. Split line at cursor. if n = 1 then -- First part ThisStartCol = StartCol ThisEndCol = .col - 1 else -- Second part ThisStartCol = ThisEndCol + 1 ThisEndCol = EndCol endif else -- Cursor not on this line or fRestoreCol deactivated. ThisStartCol = StartCol ThisEndCol = EndCol endif .col = ThisStartCol .lineg = line do forever display -14 -- Search 'xcom l '\1''TabChar display 14 -- Check rc lrc = rc if lrc then leave endif -- Check pos. if .line <> Line then leave endif if ThisEndCol > -1 then if .col > ThisEndCol then leave endif endif NextTabCol = .col + TabWidth - ((.col - 1) // TabWidth) --NextTabCol = (((.col - 1) % TabWidth) + 1) * TabWidth + 1 -- works as well NextSpaceLen = NextTabCol - .col display -14 -- Replace 'xcom c '\1''TabChar''\1''copies( ' ', NextSpaceLen) display 14 -- Check rc crc = rc if crc then leave endif rcx = 0 -- line changed -- Move cursor after replace, adapt ThisEndCol and EndCol .col = .col + NextSpaceLen if n = 1 then AddCol = AddCol + NextSpaceLen - TabLen endif if ThisEndCol > -1 then ThisEndCol = ThisEndCol + NextSpaceLen - TabLen endif if EndCol > -1 then EndCol = EndCol + NextSpaceLen - TabLen endif -- Check pos. if ThisEndCol > -1 then if .col > ThisEndCol then leave endif endif enddo enddo setsearch savesearch prestore_pos( savepos) -- Restore col if fRestoreCol then .col = .col + AddCol endif return rcx