@@ -1639,6 +1639,7 @@ export function initVim(CodeMirror) {
16391639 var promptPrefix = ( forward ) ? '/' : '?' ;
16401640 var originalQuery = getSearchState ( cm ) . getQuery ( ) ;
16411641 var originalScrollPos = cm . getScrollInfo ( ) ;
1642+ var lastQuery = ""
16421643 /** @arg {string} query @arg {boolean} ignoreCase @arg {boolean} smartCase */
16431644 function handleQuery ( query , ignoreCase , smartCase ) {
16441645 vimGlobalState . searchHistoryController . pushInput ( query ) ;
@@ -1666,6 +1667,9 @@ export function initVim(CodeMirror) {
16661667 logSearchQuery ( macroModeState , query ) ;
16671668 }
16681669 }
1670+ function pcreLabel ( ) {
1671+ return getOption ( 'pcre' ) ? '(JavaScript regexp: set pcre)' : '(Vim regexp: set nopcre)'
1672+ }
16691673 /**
16701674 * @arg {KeyboardEvent&{target:HTMLInputElement}} e
16711675 * @arg {any} query
@@ -1682,9 +1686,13 @@ export function initVim(CodeMirror) {
16821686 } else if ( keyName && keyName != '<Left>' && keyName != '<Right>' ) {
16831687 vimGlobalState . searchHistoryController . reset ( ) ;
16841688 }
1689+ lastQuery = query ;
1690+ onChange ( ) ;
1691+ }
1692+ function onChange ( ) {
16851693 var parsedQuery ;
16861694 try {
1687- parsedQuery = updateSearchQuery ( cm , query ,
1695+ parsedQuery = updateSearchQuery ( cm , lastQuery ,
16881696 true /** ignoreCase */ , true /** smartCase */ ) ;
16891697 } catch ( e ) {
16901698 // Swallow bad regexes for incremental search.
@@ -1728,7 +1736,19 @@ export function initVim(CodeMirror) {
17281736 showPrompt ( cm , {
17291737 onClose : onPromptClose ,
17301738 prefix : promptPrefix ,
1731- desc : '(JavaScript regexp)' ,
1739+ desc : dom (
1740+ 'span' ,
1741+ {
1742+ $cursor : 'pointer' ,
1743+ onmousedown : function ( e ) {
1744+ e . preventDefault ( )
1745+ setOption ( 'pcre' , ! getOption ( 'pcre' ) ) ;
1746+ this . textContent = pcreLabel ( ) ;
1747+ onChange ( ) ;
1748+ }
1749+ } ,
1750+ pcreLabel ( )
1751+ ) ,
17321752 onKeyUp : onPromptKeyUp ,
17331753 onKeyDown : onPromptKeyDown
17341754 } ) ;
@@ -2096,7 +2116,12 @@ export function initVim(CodeMirror) {
20962116 // If search is initiated with ? instead of /, negate direction.
20972117 prev = ( state . isReversed ( ) ) ? ! prev : prev ;
20982118 highlightSearchMatches ( cm , query ) ;
2099- return findNext ( cm , prev /** prev */ , query , motionArgs . repeat ) ;
2119+ var result = findNext ( cm , prev /** prev */ , query , motionArgs . repeat ) ;
2120+ if ( ! result ) {
2121+ showConfirm ( cm , 'No match found ' + query +
2122+ ( getOption ( 'pcre' ) ? ' (set nopcre to use Vim regexps)' : '' ) ) ;
2123+ }
2124+ return result ;
21002125 } ,
21012126 /**
21022127 * Find and select the next occurrence of the search query. If the cursor is currently
@@ -4930,40 +4955,49 @@ export function initVim(CodeMirror) {
49304955 /** @arg {string} str */
49314956 function translateRegex ( str ) {
49324957 // When these match, add a '\' if unescaped or remove one if escaped.
4933- var specials = '|(){' ;
4934- // Remove, but never add, a '\' for these.
4935- var unescape = '}' ;
4936- var escapeNextChar = false ;
4937- var out = [ ] ;
4938- for ( var i = - 1 ; i < str . length ; i ++ ) {
4939- var c = str . charAt ( i ) || '' ;
4940- var n = str . charAt ( i + 1 ) || '' ;
4941- var specialComesNext = ( n && specials . indexOf ( n ) != - 1 ) ;
4942- if ( escapeNextChar ) {
4943- if ( c !== '\\' || ! specialComesNext ) {
4944- out . push ( c ) ;
4958+ var modes = {
4959+ V : '|(){+?*.[$^' , // verynomagic
4960+ M : '|(){+?*.[' , // nomagic
4961+ m : '|(){+?' , // magic
4962+ v : '<>' , // verymagic
4963+ } ;
4964+ var escapes = {
4965+ '>' : '(?<=[\\w])(?=[^\\w]|$)' ,
4966+ '<' : '(?<=[^\\w]|^)(?=[\\w])' ,
4967+ } ;
4968+ var specials = modes . m ;
4969+ var regex = str . replace ( / \\ .| [ \[ | ( ) { + * ? . $ ^ < > ] / g, function ( match ) {
4970+ if ( match [ 0 ] === '\\' ) {
4971+ var nextChar = match [ 1 ] ;
4972+ if ( nextChar === '}' || specials . indexOf ( nextChar ) != - 1 ) {
4973+ return nextChar ;
49454974 }
4946- escapeNextChar = false ;
4975+ if ( nextChar in modes ) {
4976+ specials = modes [ nextChar ] ;
4977+ return '' ;
4978+ }
4979+ if ( nextChar in escapes ) {
4980+ return escapes [ nextChar ] ;
4981+ }
4982+ return match ;
49474983 } else {
4948- if ( c === '\\' ) {
4949- escapeNextChar = true ;
4950- // Treat the unescape list as special for removing, but not adding '\'.
4951- if ( n && unescape . indexOf ( n ) != - 1 ) {
4952- specialComesNext = true ;
4953- }
4954- // Not passing this test means removing a '\'.
4955- if ( ! specialComesNext || n === '\\' ) {
4956- out . push ( c ) ;
4957- }
4958- } else {
4959- out . push ( c ) ;
4960- if ( specialComesNext && n !== '\\' ) {
4961- out . push ( '\\' ) ;
4962- }
4984+ if ( specials . indexOf ( match ) != - 1 ) {
4985+ return escapes [ match ] || '\\' + match ;
49634986 }
4987+ return match ;
49644988 }
4989+ } ) ;
4990+
4991+ var i = regex . indexOf ( '\\zs' )
4992+ if ( i != - 1 ) {
4993+ regex = '(?<=' + regex . slice ( 0 , i ) + ')' + regex . slice ( i + 3 ) ;
49654994 }
4966- return out . join ( '' ) ;
4995+ i = regex . indexOf ( '\\ze' )
4996+ if ( i != - 1 ) {
4997+ regex = regex . slice ( 0 , i ) + '(?=' + regex . slice ( i + 3 ) + ')' ;
4998+ }
4999+
5000+ return regex ;
49675001 }
49685002
49695003 // Translates the replace part of a search and replace from ex (vim) syntax into
@@ -5104,6 +5138,7 @@ export function initVim(CodeMirror) {
51045138 else for ( var key in a ) {
51055139 if ( ! Object . prototype . hasOwnProperty . call ( a , key ) ) continue ;
51065140 if ( key [ 0 ] === '$' ) n . style [ key . slice ( 1 ) ] = a [ key ] ;
5141+ else if ( typeof a [ key ] == "function" ) n [ key ] = a [ key ] ;
51075142 else n . setAttribute ( key , a [ key ] ) ;
51085143 }
51095144 }
@@ -5121,15 +5156,15 @@ export function initVim(CodeMirror) {
51215156 }
51225157 cm . state . closeVimNotification = cm . openNotification ( pre , { bottom : true , duration : 0 } ) ;
51235158 } else {
5124- cm . openNotification ( pre , { bottom : true , duration : 5000 } ) ;
5159+ cm . openNotification ( pre , { bottom : true , duration : 15000 } ) ;
51255160 }
51265161 } else {
51275162 alert ( pre . innerText ) ;
51285163 }
51295164 }
51305165 /** @arg {string} prefix @arg {string} desc */
51315166 function makePrompt ( prefix , desc ) {
5132- return dom ( 'div' , { $display : 'flex' } ,
5167+ return dom ( 'div' , { $display : 'flex' , $flex : 1 } ,
51335168 dom ( 'span' , { $fontFamily : 'monospace' , $whiteSpace : 'pre' , $flex : 1 , $display : 'flex' } ,
51345169 prefix ,
51355170 dom ( 'input' , { type : 'text' , autocorrect : 'off' ,
@@ -6267,6 +6302,7 @@ export function initVim(CodeMirror) {
62676302 // Set up all the functions.
62686303 cm . state . vim . exMode = true ;
62696304 var done = false ;
6305+ var matches = 0 ;
62706306
62716307 /** @type {Pos }*/ var lastPos ;
62726308 /** @type {number }*/ var modifiedLineNumber
@@ -6281,8 +6317,23 @@ export function initVim(CodeMirror) {
62816317 } ) ;
62826318 }
62836319 function replace ( ) {
6284- var text = cm . getRange ( searchCursor . from ( ) , searchCursor . to ( ) ) ;
6285- var newText = text . replace ( query , replaceWith ) ;
6320+ var newText = '' ;
6321+ var match = searchCursor . match || searchCursor . pos && searchCursor . pos . match ;
6322+ if ( match ) {
6323+ newText = replaceWith . replace ( / \$ ( \d { 1 , 3 } | [ $ & ] ) / g, function ( _ , x ) {
6324+ if ( x == "$" ) return "$" ;
6325+ if ( x == '&' ) return match [ 0 ] ;
6326+ var x1 = x ;
6327+ while ( parseInt ( x1 ) >= match . length && x1 . length > 0 ) {
6328+ x1 = x1 . slice ( 0 , x1 . length - 1 ) ;
6329+ }
6330+ if ( x1 ) return match [ x1 ] + x . slice ( x1 . length , x . length ) ;
6331+ return _ ;
6332+ } ) ;
6333+ } else {
6334+ var text = cm . getRange ( searchCursor . from ( ) , searchCursor . to ( ) ) ;
6335+ newText = text . replace ( query , replaceWith ) ;
6336+ }
62866337 var unmodifiedLineNumber = searchCursor . to ( ) . line ;
62876338 searchCursor . replace ( newText ) ;
62886339 modifiedLineNumber = searchCursor . to ( ) . line ;
@@ -6295,6 +6346,7 @@ export function initVim(CodeMirror) {
62956346 if ( match && ! match [ 0 ] && lastMatchTo && cursorEqual ( searchCursor . from ( ) , lastMatchTo ) ) {
62966347 match = searchCursor . findNext ( ) ;
62976348 }
6349+ if ( match ) matches ++ ;
62986350 return match ;
62996351 }
63006352 function next ( ) {
@@ -6324,6 +6376,13 @@ export function initVim(CodeMirror) {
63246376 vim . lastHPos = vim . lastHSPos = lastPos . ch ;
63256377 }
63266378 if ( callback ) { callback ( ) ; }
6379+ else if ( done ) {
6380+ showConfirm ( cm ,
6381+ ( matches ? 'Found ' + matches + ' matches' : 'No matches found' ) +
6382+ ' for pattern: ' + query +
6383+ ( getOption ( 'pcre' ) ? ' (set nopcre to use Vim regexps)' : '' )
6384+ ) ;
6385+ }
63276386 }
63286387 /** @arg {KeyboardEvent} e @arg {any} _value @arg {any} close */
63296388 function onPromptKeyDown ( e , _value , close ) {
@@ -6360,7 +6419,7 @@ export function initVim(CodeMirror) {
63606419 // Actually do replace.
63616420 next ( ) ;
63626421 if ( done ) {
6363- showConfirm ( cm , 'No matches for ' + query . source ) ;
6422+ showConfirm ( cm , 'No matches for ' + query + ( getOption ( 'pcre' ) ? ' (set nopcre to use vim regexps)' : '' ) ) ;
63646423 return ;
63656424 }
63666425 if ( ! confirm ) {
0 commit comments