/****************************** Module Header ******************************* * * Module Name: comment.e * * Copyright (c) Netlabs EPM Distribution Project 2002 * * $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 com, comment call NextCmdAltersText() call CommentLines( arg(1), 'C') defc ucom, uncomment call NextCmdAltersText() call CommentLines( arg(1), 'U') ; Hint for inserting a line: ; ; -- Prepend a new line ; top ; insertline '--- New line added at top ---' -- insertline adds a line before the current ; ; -- Append a new line ; bottom ; end_line; split -- this inserts a new line after the current ; .line = .line + 1 -- go to new line ; replaceline '--- New line added at bottom ---' ; --------------------------------------------------------------------------- ; arg(1) = single-line comment char(s) ; arg(2) = ('U'|'C') U: uncomment, C: comment (default) ; Comment: ; - Every marked line or line with marked chars will be commented out. ; - Each mark type is converted to line mark. ; - If unmarked, the line set with the same or larger indent indent as ; the cursor line is processed. ; - Prefers single-line comments (if defined). ; - Multi-line comments are added as new lines above and below the mark. ; Uncomment: ; - Every marked line or line with marked chars will be uncommented. ; - Each mark type is converted to line mark. ; - If unmarked, the line set with the same or larger indent indent as ; the cursor line is processed. ; - Doesn't uncomment if the mark contains any uncommented line. ; - Determines if a space was added behind the comment char. ; - Tries every comment char, starts with single-line comments. ; - Every single-line comment must be at line start. ; - Every multi-line comment must be on a separate line. ; - Doesn't remove multi-line comments, that appear on every line. defproc CommentLines -- Slc : single-line comment char(s), ? = 1...3 -- SlcCol : column for the Slc, 0 means: allowed at every column, not used here -- fSlcAddSpace : (0|1) shall a space be added/removed after the Slc -- MlcStart : multi-line comment char(s), ? = 1...2, start string -- MlcEnd : multi-line comment char(s), ? = 1...2, end string -- fCase : (0|1) for uncomment only: respect case when locating Slc string in line Slc = '' fSlcAddSpace = 0 MlcStart = '' MlcEnd = '' PrefCom = '' PrefComType = 'S' PrefComNum = 1 fCase = QueryModeKey( mode, 'CaseSensitive', '1') -- default is case-sensitive AdjLine = 0 AdjCol = 0 mode = GetMode() if arg(1) > '' then -- if a single-line comment char was submitted as arg(1) Slc = strip( arg(1)) fSlcAddSpace = (rightstr( arg(1), 1) == ' ') -- add a space if none was specified else PrefCom = QueryModeKey( mode, 'PreferredComment') --call dprintf('comment', 'Preferred: 'PrefCom) if PrefCom = '' then -- Handle no def here Slc = word( QueryModeKey( mode, 'LineComment'), 1) if Slc = '' then MlcStart = word( QueryModeKey( mode, 'MultiLineCommentStart'), 1) MlcEnd = word( QueryModeKey( mode, 'MultiLineCommentEnd' ), 1) else fSlcAddSpace = word( QueryModeKey( mode, 'LineCommentAddSpace'), 1) endif else PrefComType = upcase( leftstr( PrefCom, 1)) PrefComNum = substr( PrefCom, 2) if PrefComNum = '' then PrefComNum = 1 elseif not IsNum( PrefComNum) then PrefComNum = 1 endif --call dprintf('comment', 'Type num: 'PrefComType PrefComNum) if PrefComType = 'L' | PrefComType = 'S' then Slc = word( QueryModeKey( mode, 'LineComment'), PrefComNum) fSlcAddSpace = word( QueryModeKey( mode, 'LineCommentAddSpace'), PrefComNum) --call dprintf('comment', 'Slc Add: 'Slc SlcAddSpace) else MlcStart = word( QueryModeKey( mode, 'MultiLineCommentStart'), PrefComNum) MlcEnd = word( QueryModeKey( mode, 'MultiLineCommentEnd' ), PrefComNum) --call dprintf('comment', 'MlcS MlcE: 'MlcStart MlcEnd) endif endif endif fWasMarked = FileIsMarked() if fWasMarked then MarkToLineMark() else MarkLineSetAtCursor() endif getmark firstline, lastline, firstcol, lastcol, fid mt = marktype() first = firstline last = lastline -- no additional undo state supression required psave_pos( SavedPos) SavedLine = .line if abbrev( 'U', upcase( arg(2))) then action = 'UNCOMMENT' else action = 'COMMENT' endif if action = 'COMMENT' then -- Single-line comments are preferred to multi-line comments if Slc <> '' then -- if a single-line comment is defined -- Add a single-line comment if fSlcAddSpace then Slc = Slc' ' endif do l = first to last .line = l Oldline = textline( .line) Newline = Slc''Oldline replaceline Newline enddo -- Adjust col if SavedLine >= first & SavedLine <= last then -- Cursor was in mark AdjCol = length( Slc) endif elseif MlcStart <> '' & MlcEnd <> '' then -- if a multi-line comment is defined -- Add a new line and the comment start .line = first -- go to first marked line insertline MlcStart -- insertline adds a line before the current -- Add a new line and the comment end .line = last + 1 -- go to last marked line (respect that a line was added before) end_line -- this inserts a new line ... split -- ... after the current .line = .line + 1 -- go to new line replaceline MlcEnd -- Adjust line if SavedLine >= first then if SavedLine <= last then -- Cursor was in mark AdjLine = 1 else -- Cursor was below mark AdjLine = 2 endif endif endif else -- UNCOMMENT -- Remove single-line comments fSlcProcessed = 0 SlcList = QueryModeKey( mode, 'LineComment') SlcAddSpaceList = QueryModeKey( mode, 'LineCommentAddSpace') do i = 1 to words( SlcList) -- try every possible single-line comment fiterate_i = 0 Slc = word( SlcList, i) fSlcAddSpace = word( SlcAddSpaceList, i) SlcSpace = Slc' ' len = length( Slc) lenSpace = length( SlcSpace) -- First run: check if all lines are commented and if there's a space after every Slc do l = first to last .line = l Oldline = textline( .line) if fCase = 0 then CaseOldline = upcase( Oldline) CaseSlcSpace = upcase( SlcSpace) CaseSlc = upcase( Slc) else CaseOldline = Oldline CaseSlcSpace = SlcSpace CaseSlc = Slc endif if leftstr( CaseOldline, lenSpace) <> CaseSlcSpace then -- Try Slc without space. if leftstr( CaseOldline, len) = CaseSlc then if CaseOldline <> CaseSlc then -- Reset it only if this is not a blank commented line fSlcAddSpace = 0 endif else -- Uncommented line in mark, try next comment char fiterate_i = 1 leave endif endif enddo -- l if fiterate_i = 1 then iterate endif if fSlcAddSpace = 1 then len = lenSpace -- add 1 to amount of chars removed endif -- Second run: remove comments -- At this point we are sure, that every line is commented. do l = first to last .line = l Oldline = textline( .line) if fCase = 0 then CaseOldline = upcase( Oldline) CaseSlc = upcase( Slc) else CaseOldline = Oldline CaseSlc = Slc endif if CaseOldline = CaseSlc then -- for commented blank lines missing the space Newline = '' elseif length( Oldline) > len then Newline = substr( Oldline, len + 1) else Newline = '' endif replaceline Newline enddo -- l fSlcProcessed = 1 AdjCol = -len leave enddo -- i = 1 to words(SlcList) -- Remove multi-line comments if fSlcProcessed = 0 then prestore_pos( SavedPos) -- possible extension here: remove multi-line comments if they are found in every line MlcStartList = QueryModeKey( mode, 'MultiLineCommentStart') MlcEndList = QueryModeKey( mode, 'MultiLineCommentEnd') do i = 1 to words( MlcStartList) MlcStart = word( MlcStartList, i) MlcEnd = word( MlcEndList, i) MlcStartLine = -1 MlcEndLine = -1 line = textline( first) if strip( line, 't') = MlcStart then MlcStartLine = first else line = textline( first - 1) if strip( line, 't') = MlcStart then MlcStartLine = first - 1 firstline = firstline - 1 -- for mark restore endif endif if MlcStartLine < 0 then sayerror 'Comment start "'MlcStart'" not found in mark or at the line before' elseif MlcEndLine < 0 then line = textline( last) if strip( line, 't') = MlcEnd then MlcEndLine = last lastline = lastline - 1 -- for mark restore lastcol = 0 -- for mark restore else line = textline( last + 1) if strip( line, 't' ) = MlcEnd then MlcEndLine = last + 1 lastline = lastline - 1 -- for mark restore endif endif if MlcEndLine < 0 then sayerror 'Comment end "'MlcEnd'" not found in mark or at the line after' endif endif if MlcStartLine >= 0 and MlcEndLine >= 0 then if .line >= MlcEndLine then AdjLine = -2 elseif .line = MlcEndLine - 1 then AdjLine = -1 endif .line = MlcEndLine deleteline .line = MlcStartLine deleteline call pset_mark( firstline, lastline, firstcol, lastcol, mt, fid) leave endif enddo -- i = 1 to words(MlcStartList) endif -- fSlcProcessed = 0 endif -- action = 'COMMENT' prestore_pos( SavedPos) .line = .line + AdjLine .col = .col + AdjCol return