@@ -13,7 +13,7 @@ import {
1313 IModelContentChangedLinesDeletedEvent , IModelContentChangedLinesInsertedEvent
1414} from 'vs/editor/common/editorCommon' ;
1515import { Model } from 'vs/editor/common/model/model' ;
16- import { TextModel , IParsedSearchRequest } from 'vs/editor/common/model/textModel' ;
16+ import { TextModel } from 'vs/editor/common/model/textModel' ;
1717
1818// --------- utils
1919
@@ -599,6 +599,77 @@ suite('Editor Model - Find', () => {
599599 ) ;
600600 } ) ;
601601
602+ test ( 'multiline find with line beginning regex' , ( ) => {
603+ assertFindMatches (
604+ [
605+ 'if' ,
606+ 'else' ,
607+ '' ,
608+ 'if' ,
609+ 'else'
610+ ] . join ( '\n' ) ,
611+ '^if\\nelse' , true , false , false ,
612+ [
613+ [ 1 , 1 , 2 , 5 ] ,
614+ [ 4 , 1 , 5 , 5 ]
615+ ]
616+ ) ;
617+ } ) ;
618+
619+ test ( 'matching empty lines using boundary expression' , ( ) => {
620+ assertFindMatches (
621+ [
622+ 'if' ,
623+ '' ,
624+ 'else' ,
625+ ' ' ,
626+ 'if' ,
627+ ' ' ,
628+ 'else'
629+ ] . join ( '\n' ) ,
630+ '^\\s*$\\n' , true , false , false ,
631+ [
632+ [ 2 , 1 , 3 , 1 ] ,
633+ [ 4 , 1 , 5 , 1 ] ,
634+ [ 6 , 1 , 7 , 1 ]
635+ ]
636+ ) ;
637+ } ) ;
638+
639+ test ( 'matching lines starting with A and ending with B' , ( ) => {
640+ assertFindMatches (
641+ [
642+ 'a if b' ,
643+ 'a' ,
644+ 'ab' ,
645+ 'eb'
646+ ] . join ( '\n' ) ,
647+ '^a.*b$' , true , false , false ,
648+ [
649+ [ 1 , 1 , 1 , 7 ] ,
650+ [ 3 , 1 , 3 , 3 ]
651+ ]
652+ ) ;
653+ } ) ;
654+
655+ test ( 'multiline find with line ending regex' , ( ) => {
656+ assertFindMatches (
657+ [
658+ 'if' ,
659+ 'else' ,
660+ '' ,
661+ 'if' ,
662+ 'elseif' ,
663+ 'else'
664+ ] . join ( '\n' ) ,
665+ 'if\\nelse$' , true , false , false ,
666+ [
667+ [ 1 , 1 , 2 , 5 ] ,
668+ [ 5 , 5 , 6 , 5 ]
669+ ]
670+ ) ;
671+ } ) ;
672+
602673 test ( 'issue #4836 - ^.*$' , ( ) => {
603674 assertFindMatches (
604675 [
@@ -619,7 +690,97 @@ suite('Editor Model - Find', () => {
619690 ) ;
620691 } ) ;
621692
622- function assertParseSearchResult ( searchString :string , isRegex :boolean , matchCase :boolean , wholeWord :boolean , expected :IParsedSearchRequest ) : void {
693+ test ( 'findNextMatch without regex' , ( ) => {
694+ var testObject = new TextModel ( [ ] , TextModel . toRawText ( 'line line one\nline two\nthree' , TextModel . DEFAULT_CREATION_OPTIONS ) ) ;
695+
696+ let actual = testObject . findNextMatch ( 'line' , { lineNumber : 1 , column : 1 } , false , false , false ) ;
697+ assert . equal ( new Range ( 1 , 1 , 1 , 5 ) . toString ( ) , actual . toString ( ) ) ;
698+
699+ actual = testObject . findNextMatch ( 'line' , actual . getEndPosition ( ) , false , false , false ) ;
700+ assert . equal ( new Range ( 1 , 6 , 1 , 10 ) . toString ( ) , actual . toString ( ) ) ;
701+
702+ actual = testObject . findNextMatch ( 'line' , { lineNumber : 1 , column : 3 } , false , false , false ) ;
703+ assert . equal ( new Range ( 1 , 6 , 1 , 10 ) . toString ( ) , actual . toString ( ) ) ;
704+
705+ actual = testObject . findNextMatch ( 'line' , actual . getEndPosition ( ) , false , false , false ) ;
706+ assert . equal ( new Range ( 2 , 1 , 2 , 5 ) . toString ( ) , actual . toString ( ) ) ;
707+
708+ actual = testObject . findNextMatch ( 'line' , actual . getEndPosition ( ) , false , false , false ) ;
709+ assert . equal ( new Range ( 1 , 1 , 1 , 5 ) . toString ( ) , actual . toString ( ) ) ;
710+
711+ testObject . dispose ( ) ;
712+ } ) ;
713+
714+ test ( 'findNextMatch with beginning boundary regex' , ( ) => {
715+ var testObject = new TextModel ( [ ] , TextModel . toRawText ( 'line one\nline two\nthree' , TextModel . DEFAULT_CREATION_OPTIONS ) ) ;
716+
717+ let actual = testObject . findNextMatch ( '^line' , { lineNumber : 1 , column : 1 } , true , false , false ) ;
718+ assert . equal ( new Range ( 1 , 1 , 1 , 5 ) . toString ( ) , actual . toString ( ) ) ;
719+
720+ actual = testObject . findNextMatch ( '^line' , actual . getEndPosition ( ) , true , false , false ) ;
721+ assert . equal ( new Range ( 2 , 1 , 2 , 5 ) . toString ( ) , actual . toString ( ) ) ;
722+
723+ actual = testObject . findNextMatch ( '^line' , { lineNumber : 1 , column : 3 } , true , false , false ) ;
724+ assert . equal ( new Range ( 2 , 1 , 2 , 5 ) . toString ( ) , actual . toString ( ) ) ;
725+
726+ actual = testObject . findNextMatch ( '^line' , actual . getEndPosition ( ) , true , false , false ) ;
727+ assert . equal ( new Range ( 1 , 1 , 1 , 5 ) . toString ( ) , actual . toString ( ) ) ;
728+
729+ testObject . dispose ( ) ;
730+ } ) ;
731+
732+ test ( 'findNextMatch with beginning boundary regex and line has repetitive beginnings' , ( ) => {
733+ var testObject = new TextModel ( [ ] , TextModel . toRawText ( 'line line one\nline two\nthree' , TextModel . DEFAULT_CREATION_OPTIONS ) ) ;
734+
735+ let actual = testObject . findNextMatch ( '^line' , { lineNumber : 1 , column : 1 } , true , false , false ) ;
736+ assert . equal ( new Range ( 1 , 1 , 1 , 5 ) . toString ( ) , actual . toString ( ) ) ;
737+
738+ actual = testObject . findNextMatch ( '^line' , actual . getEndPosition ( ) , true , false , false ) ;
739+ assert . equal ( new Range ( 2 , 1 , 2 , 5 ) . toString ( ) , actual . toString ( ) ) ;
740+
741+ actual = testObject . findNextMatch ( '^line' , { lineNumber : 1 , column : 3 } , true , false , false ) ;
742+ assert . equal ( new Range ( 2 , 1 , 2 , 5 ) . toString ( ) , actual . toString ( ) ) ;
743+
744+ actual = testObject . findNextMatch ( '^line' , actual . getEndPosition ( ) , true , false , false ) ;
745+ assert . equal ( new Range ( 1 , 1 , 1 , 5 ) . toString ( ) , actual . toString ( ) ) ;
746+
747+ testObject . dispose ( ) ;
748+ } ) ;
749+
750+ test ( 'findNextMatch with beginning boundary multiline regex and line has repetitive beginnings' , ( ) => {
751+ var testObject = new TextModel ( [ ] , TextModel . toRawText ( 'line line one\nline two\nline three\nline four' , TextModel . DEFAULT_CREATION_OPTIONS ) ) ;
752+
753+ let actual = testObject . findNextMatch ( '^line.*\\nline' , { lineNumber : 1 , column : 1 } , true , false , false ) ;
754+ assert . equal ( new Range ( 1 , 1 , 2 , 5 ) . toString ( ) , actual . toString ( ) ) ;
755+
756+ actual = testObject . findNextMatch ( '^line.*\\nline' , actual . getEndPosition ( ) , true , false , false ) ;
757+ assert . equal ( new Range ( 3 , 1 , 4 , 5 ) . toString ( ) , actual . toString ( ) ) ;
758+
759+ actual = testObject . findNextMatch ( '^line.*\\nline' , { lineNumber : 2 , column : 1 } , true , false , false ) ;
760+ assert . equal ( new Range ( 2 , 1 , 3 , 5 ) . toString ( ) , actual . toString ( ) ) ;
761+
762+ testObject . dispose ( ) ;
763+ } ) ;
764+
765+ test ( 'findNextMatch with ending boundary regex' , ( ) => {
766+ var testObject = new TextModel ( [ ] , TextModel . toRawText ( 'one line line\ntwo line\nthree' , TextModel . DEFAULT_CREATION_OPTIONS ) ) ;
767+
768+ let actual = testObject . findNextMatch ( 'line$' , { lineNumber : 1 , column : 1 } , true , false , false ) ;
769+ assert . equal ( new Range ( 1 , 10 , 1 , 14 ) . toString ( ) , actual . toString ( ) ) ;
770+
771+ actual = testObject . findNextMatch ( 'line$' , { lineNumber : 1 , column : 4 } , true , false , false ) ;
772+ assert . equal ( new Range ( 1 , 10 , 1 , 14 ) . toString ( ) , actual . toString ( ) ) ;
773+
774+ actual = testObject . findNextMatch ( 'line$' , actual . getEndPosition ( ) , true , false , false ) ;
775+ assert . equal ( new Range ( 2 , 5 , 2 , 9 ) . toString ( ) , actual . toString ( ) ) ;
776+
777+ actual = testObject . findNextMatch ( 'line$' , actual . getEndPosition ( ) , true , false , false ) ;
778+ assert . equal ( new Range ( 1 , 10 , 1 , 14 ) . toString ( ) , actual . toString ( ) ) ;
779+
780+ testObject . dispose ( ) ;
781+ } ) ;
782+
783+ function assertParseSearchResult ( searchString :string , isRegex :boolean , matchCase :boolean , wholeWord :boolean , expected :RegExp ) : void {
623784 let actual = TextModel . parseSearchRequest ( searchString , isRegex , matchCase , wholeWord ) ;
624785 assert . deepEqual ( actual , expected ) ;
625786 }
@@ -631,24 +792,24 @@ suite('Editor Model - Find', () => {
631792 } ) ;
632793
633794 test ( 'parseSearchRequest non regex' , ( ) => {
634- assertParseSearchResult ( 'foo' , false , false , false , { regex : / f o o / gi, isMultiline : false } ) ;
635- assertParseSearchResult ( 'foo' , false , false , true , { regex : / \b f o o \b / gi, isMultiline : false } ) ;
636- assertParseSearchResult ( 'foo' , false , true , false , { regex : / f o o / g, isMultiline : false } ) ;
637- assertParseSearchResult ( 'foo' , false , true , true , { regex : / \b f o o \b / g, isMultiline : false } ) ;
638- assertParseSearchResult ( 'foo\\n' , false , false , false , { regex : / f o o \\ n / gi, isMultiline : false } ) ;
639- assertParseSearchResult ( 'foo\\\\n' , false , false , false , { regex : / f o o \\ \\ n / gi, isMultiline : false } ) ;
640- assertParseSearchResult ( 'foo\\r' , false , false , false , { regex : / f o o \\ r / gi, isMultiline : false } ) ;
641- assertParseSearchResult ( 'foo\\\\r' , false , false , false , { regex : / f o o \\ \\ r / gi, isMultiline : false } ) ;
795+ assertParseSearchResult ( 'foo' , false , false , false , / f o o / gi) ;
796+ assertParseSearchResult ( 'foo' , false , false , true , / \b f o o \b / gi) ;
797+ assertParseSearchResult ( 'foo' , false , true , false , / f o o / g) ;
798+ assertParseSearchResult ( 'foo' , false , true , true , / \b f o o \b / g) ;
799+ assertParseSearchResult ( 'foo\\n' , false , false , false , / f o o \\ n / gi) ;
800+ assertParseSearchResult ( 'foo\\\\n' , false , false , false , / f o o \\ \\ n / gi) ;
801+ assertParseSearchResult ( 'foo\\r' , false , false , false , / f o o \\ r / gi) ;
802+ assertParseSearchResult ( 'foo\\\\r' , false , false , false , / f o o \\ \\ r / gi) ;
642803 } ) ;
643804
644805 test ( 'parseSearchRequest regex' , ( ) => {
645- assertParseSearchResult ( 'foo' , true , false , false , { regex : / f o o / gi, isMultiline : false } ) ;
646- assertParseSearchResult ( 'foo' , true , false , true , { regex : / \b f o o \b / gi, isMultiline : false } ) ;
647- assertParseSearchResult ( 'foo' , true , true , false , { regex : / f o o / g, isMultiline : false } ) ;
648- assertParseSearchResult ( 'foo' , true , true , true , { regex : / \b f o o \b / g, isMultiline : false } ) ;
649- assertParseSearchResult ( 'foo\\n' , true , false , false , { regex : / f o o \n / gi , isMultiline : true } ) ;
650- assertParseSearchResult ( 'foo\\\\n' , true , false , false , { regex : / f o o \\ n / gi, isMultiline : false } ) ;
651- assertParseSearchResult ( 'foo\\r' , true , false , false , { regex : / f o o \r / gi , isMultiline : true } ) ;
652- assertParseSearchResult ( 'foo\\\\r' , true , false , false , { regex : / f o o \\ r / gi, isMultiline : false } ) ;
806+ assertParseSearchResult ( 'foo' , true , false , false , / f o o / gi) ;
807+ assertParseSearchResult ( 'foo' , true , false , true , / \b f o o \b / gi) ;
808+ assertParseSearchResult ( 'foo' , true , true , false , / f o o / g) ;
809+ assertParseSearchResult ( 'foo' , true , true , true , / \b f o o \b / g) ;
810+ assertParseSearchResult ( 'foo\\n' , true , false , false , / f o o \n / gim ) ;
811+ assertParseSearchResult ( 'foo\\\\n' , true , false , false , / f o o \\ n / gi) ;
812+ assertParseSearchResult ( 'foo\\r' , true , false , false , / f o o \r / gim ) ;
813+ assertParseSearchResult ( 'foo\\\\r' , true , false , false , / f o o \\ r / gi) ;
653814 } ) ;
654815} ) ;
0 commit comments