ListView.st
changeset 5546 89bcf7a74c6e
parent 5544 50fae0f51891
child 5552 58ac0bd34b7b
child 5585 c14ee2bcedea
--- a/ListView.st	Fri Jan 15 20:43:55 2016 +0100
+++ b/ListView.st	Fri Jan 15 22:53:02 2016 +0100
@@ -4707,7 +4707,8 @@
 searchBackwardUsingSpec:searchSpec startingAtLine:startLine col:startCol ifFound:block1 ifAbsent:block2
     "search for a pattern, if found evaluate block1 with row/col as arguments, if not
      found evaluate block2.
-     Sorry, but pattern is no regular expression pattern (yet)"
+     Sorry, but pattern is no regular expression pattern (yet).
+     Also, wraps are not done when searching backward."
 
     |lineString
      pattern ignCase match fullWord atBeginOfLineOnly
@@ -4756,10 +4757,8 @@
                     lineString isString ifTrue:[
                         "/ quick check if pattern is present
                         col1 := lineString
-                                findString:pattern
-                                startingAt:1
-                                ifAbsent:0
-                                caseSensitive: ignCase not.
+                                findString:pattern startingAt:1
+                                ifAbsent:0 caseSensitive: ignCase not.
                         col1 ~~ 0 ifTrue:[
                             lineSize := lineString size.
                             col == -999 ifTrue:[col := lineSize - patternSize + 1].
@@ -4852,20 +4851,23 @@
 !
 
 searchForwardUsingSpec:searchSpec startingAtLine:startLine col:startCol ifFound:block1 ifAbsent:block2
-    "search for a pattern, if found evaluate block1 with row/col as arguments, if not
-     found evaluate block2."
-
-    |lineString col pattern match ignCase fullWord atBeginOfLineOnly
-     patternSize
+    "search for a pattern, if found evaluate block1 with row/col as arguments, 
+     if not found evaluate block2. 
+     If the block is a three-arg block, it gets the end-col (or nil, if not found)"
+
+    |lineString col pattern match regexMatch ignCase fullWord atBeginOfLineOnly
+     wrapAtEndOfText patternSize matcher lnr   "{Class: SmallInteger}"  
      line1 "{Class: SmallInteger}"
      line2 "{Class: SmallInteger}"
-     p realPattern|
+     p realPattern runner foundCol endCol|
 
     pattern := searchSpec pattern.
     match := searchSpec match.
+    regexMatch := searchSpec regexMatch.
     ignCase := searchSpec ignoreCase.
     fullWord := searchSpec fullWord.
     atBeginOfLineOnly := searchSpec atBeginOfLineOnly.
+    wrapAtEndOfText := searchSpec wrapAtEndOfText.
 
     patternSize := pattern size.
     (list notNil and:[patternSize ~~ 0]) ifTrue:[
@@ -4875,76 +4877,92 @@
             line1 := startLine.
             line2 := list size.
 
-            (match and:[pattern includesUnescapedMatchCharacters]) ifTrue:[
-                "perform a findMatchString (matching)"
-                p := pattern species new:0.
-                (pattern startsWith:$*) ifFalse:[
-                    p := p , '*'
-                ].
-                p := p , pattern.
-                (pattern endsWith:$*) ifFalse:[
-                    p := p , '*'
+            "/ call searchBlock with lnr, col, and line. Cares for wrap
+            runner := 
+                [:searchBlock |
+                    |didWrap|
+                    
+                    lnr := line1.
+                    didWrap := false.
+                    [lnr <= line2] whileTrue:[
+                        lineString := list at:lnr.
+                        lineString notNil ifTrue:[
+                            lineString := lineString asString string.
+                            lineString isString ifTrue:[
+                                searchBlock value:lnr value:col value:lineString
+                            ]
+                        ].
+                        col := 1.
+                        lnr := lnr + 1.
+                        lnr > line2 ifTrue:[
+                            (wrapAtEndOfText and:[didWrap not]) ifTrue:[
+                                didWrap := true.
+                                lnr := 1.
+                                line2 := line1-1.
+                            ].   
+                        ].    
+                   ].
+                    
                 ].
-                realPattern := pattern.
-                (realPattern startsWith:$*) ifTrue:[
-                    realPattern := realPattern copyFrom:2
-                ].
-                line1 to:line2 do:[:lnr |
-                    lineString := list at:lnr.
-                    lineString notNil ifTrue:[
-                        lineString := lineString asString string.
-                        lineString isString ifTrue:[
-                            "/ first a crude check ...
+                
+            (match and:[regexMatch]) ifTrue:[
+                "perform a findMatchString (regex matching)"
+                matcher := ignCase ifTrue:[pattern asRegexIgnoringCase] ifFalse:[pattern asRegex]. 
+                runner 
+                    value:[:lnr :col :lineString |
+                        "/ first a crude check ...
+                        (matcher hasMatchesIn:lineString) ifTrue:[
+                            "/ find which match to show
+                            1 to:matcher subexpressionCount do:[:i | 
+                                foundCol := matcher subBeginning:i.
+                                endCol := matcher subEnd:i.
+                                (foundCol notNil and: [endCol notNil]) ifTrue: [
+                                    foundCol := foundCol + 1. "/ regex uses 0-based indexes (sigh)
+                                    foundCol >= col ifTrue:[
+                                        (atBeginOfLineOnly not or:[foundCol == 1]) ifTrue:[
+                                            ^ block1 value:lnr value:foundCol optionalArgument:endCol.
+                                        ]]]]]].
+            ] ifFalse:[    
+                (match and:[regexMatch or:[pattern includesUnescapedMatchCharacters]]) ifTrue:[
+                    "perform a findMatchString (glob matching)"
+                    p := pattern species new:0.
+                    (pattern startsWith:$*) ifFalse:[p := p , '*'].
+                    p := p , pattern.
+                    (pattern endsWith:$*) ifFalse:[p := p , '*'].
+                    realPattern := pattern.
+                    (realPattern startsWith:$*) ifTrue:[
+                        realPattern := realPattern copyFrom:2
+                    ].
+                    runner 
+                        value:[:lnr :col :lineString |
                             (p match:lineString caseSensitive:ignCase not) ifTrue:[
                                 "/ ok, there it is; look at which position
-                                col := lineString
-                                        findMatchString:realPattern
-                                        startingAt:col
-                                        caseSensitive:ignCase not
-                                        ifAbsent:0.
-                                col ~~ 0 ifTrue:[
-                                    (atBeginOfLineOnly not or:[col == 1]) ifTrue:[
-                                        ^ block1 value:lnr value:col.
+                                foundCol := lineString
+                                        findMatchString:realPattern startingAt:col
+                                        caseSensitive:ignCase not ifAbsent:0.
+                                foundCol ~~ 0 ifTrue:[
+                                    (atBeginOfLineOnly not or:[foundCol == 1]) ifTrue:[
+                                        ^ block1 value:lnr value:foundCol optionalArgument:nil.
+                                    ]]]].
+                ] ifFalse:[
+                    "perform a findString (no matching)"
+                    p := pattern.
+                    runner 
+                        value:[:lnr :col :lineString |
+                            foundCol := lineString
+                                    findString:p startingAt:col ifAbsent:0 caseSensitive: ignCase not.
+                            foundCol ~~ 0 ifTrue:[
+                                (fullWord not
+                                    or:[ (self findBeginOfWordAtLine:lnr col:foundCol) == foundCol
+                                          and:[ (self findEndOfWordAtLine:lnr col:foundCol) == (foundCol + patternSize - 1) ]]
+                                ) ifTrue:[
+                                    (atBeginOfLineOnly not or:[foundCol == 1]) ifTrue:[
+                                        ^ block1 value:lnr value:foundCol optionalArgument:nil.
                                     ]
                                 ]
                             ]
                         ].
-                    ].
-                    col := 1
-                ]
-            ] ifFalse:[
-                "perform a findString (no matching)"
-                p := pattern "withoutMatchEscapes".
-                line1 to:line2 do:[:lnr |
-                    lineString := list at:lnr.
-                    lineString notNil ifTrue:[
-                        lineString := lineString asString string.
-                        lineString isString ifTrue:[
-                            col := lineString
-                                    findString:p
-                                    startingAt:col
-                                    ifAbsent:0
-                                    caseSensitive: ignCase not.
-                            col ~~ 0 ifTrue:[
-"/Transcript showCR:'---'.
-"/Transcript showCR:lineString.
-"/Transcript showCR:col.
-"/Transcript showCR:(self findBeginOfWordAtLine:lnr col:col).
-"/Transcript showCR:(self findEndOfWordAtLine:lnr col:col).
-"/Transcript showCR:(lineString copyFrom:(self findBeginOfWordAtLine:lnr col:col) to:(self findEndOfWordAtLine:lnr col:col)).
-                                (fullWord not
-                                    or:[ (self findBeginOfWordAtLine:lnr col:col) == col
-                                          and:[ (self findEndOfWordAtLine:lnr col:col) == (col + patternSize - 1) ]]
-                                ) ifTrue:[
-                                    (atBeginOfLineOnly not or:[col == 1]) ifTrue:[
-                                        ^ block1 value:lnr value:col.
-                                    ]
-                                ]
-                            ]
-                        ]
-                    ].
-                    col := 1
-                ]
+                ].
             ].
         ]
     ].