@@ -297,6 +297,7 @@ export function initVim(CM) {
297297 { name : 'startinsert' , shortName : 'start' } ,
298298 { name : 'nohlsearch' , shortName : 'noh' } ,
299299 { name : 'yank' , shortName : 'y' } ,
300+ { name : 'put' , shortName : 'pu' } ,
300301 { name : 'delmarks' , shortName : 'delm' } ,
301302 { name : 'marks' , excludeFromCommandHistory : true } ,
302303 { name : 'registers' , shortName : 'reg' , excludeFromCommandHistory : true } ,
@@ -1983,6 +1984,12 @@ export function initVim(CM) {
19831984 if ( vim . visualMode ) {
19841985 promptOptions . value = '\'<,\'>' ;
19851986 promptOptions . selectValueOnOpen = false ;
1987+ } else {
1988+ var repeat = vim . inputState . getRepeat ( ) ;
1989+ if ( repeat > 1 ) {
1990+ promptOptions . value = '.,.+' + ( repeat - 1 ) ;
1991+ promptOptions . selectValueOnOpen = false ;
1992+ }
19861993 }
19871994 showPrompt ( cm , promptOptions ) ;
19881995 }
@@ -2901,6 +2908,9 @@ export function initVim(CM) {
29012908 vimGlobalState . registerController . pushText (
29022909 args . registerName , 'yank' ,
29032910 text , args . linewise , vim . visualBlock ) ;
2911+
2912+ var lineCount = Math . abs ( cm . getCursor ( "end" ) . line - cm . getCursor ( "start" ) . line ) || 1 ;
2913+ showConfirm ( cm , lineCount + ' lines yanked' + ( args . registerName ? ' into "' + args . registerName : '' ) , false , 1500 ) ;
29042914 return endPos ;
29052915 } ,
29062916 rot13 : function ( cm , args , ranges , oldAnchor , newHead ) {
@@ -3291,7 +3301,7 @@ export function initVim(CM) {
32913301 if ( actionArgs . repeat > 1 ) {
32923302 text = Array ( actionArgs . repeat + 1 ) . join ( text ) ;
32933303 }
3294- var linewise = register . linewise ;
3304+ var linewise = actionArgs . linewise == undefined ? register . linewise : actionArgs . linewise ;
32953305 var blockwise = register . blockwise ;
32963306 var textLines = blockwise ? text . split ( '\n' ) : undefined ;
32973307 if ( textLines ) {
@@ -5288,8 +5298,8 @@ export function initVim(CM) {
52885298 return n ;
52895299 }
52905300
5291- /** @arg {CodeMirror} cm @arg {any} template @arg {boolean} [long]*/
5292- function showConfirm ( cm , template , long ) {
5301+ /** @arg {CodeMirror} cm @arg {any} template @arg {boolean} [long] @arg {number} [duration] */
5302+ function showConfirm ( cm , template , long , duration ) {
52935303 var pre = dom ( 'div' , { $color : 'red' , $whiteSpace : 'pre' , class : 'cm-vim-message' } , template ) ;
52945304 if ( cm . openNotification ) {
52955305 if ( long ) {
@@ -5299,9 +5309,9 @@ export function initVim(CM) {
52995309 }
53005310 cm . state . closeVimNotification = cm . openNotification ( pre , { bottom : true , duration : 0 } ) ;
53015311 } else {
5302- cm . openNotification ( pre , { bottom : true , duration : 15000 } ) ;
5312+ cm . openNotification ( pre , { bottom : true , duration : duration || 15000 } ) ;
53035313 }
5304- } else {
5314+ } else if ( ! duration ) {
53055315 alert ( pre . innerText ) ;
53065316 }
53075317 }
@@ -5628,7 +5638,7 @@ export function initVim(CM) {
56285638 this . parseInput_ ( cm , inputStream , params ) ;
56295639 } catch ( e ) {
56305640 showConfirm ( cm , e + "" ) ;
5631- throw e ;
5641+ return ;
56325642 }
56335643
56345644 if ( vim . visualMode ) {
@@ -5689,6 +5699,12 @@ export function initVim(CM) {
56895699 if ( inputStream . eat ( '%' ) ) {
56905700 result . line = cm . firstLine ( ) ;
56915701 result . lineEnd = cm . lastLine ( ) ;
5702+ } else if ( inputStream . eat ( '*' ) ) {
5703+ var lastSelection = cm . state . vim . lastSelection ;
5704+ var anchor = lastSelection ?. anchorMark . find ( ) ?. line || 0 ;
5705+ var head = lastSelection ?. headMark . find ( ) ?. line || 0 ;
5706+ result . line = Math . max ( anchor , head ) ;
5707+ result . lineEnd = Math . min ( anchor , head ) ;
56925708 } else {
56935709 result . line = this . parseLineSpec_ ( cm , inputStream ) ;
56945710 if ( result . line !== undefined && inputStream . eat ( ',' ) ) {
@@ -5708,6 +5724,7 @@ export function initVim(CM) {
57085724 result . selectionLineEnd = result . lineEnd ;
57095725 }
57105726
5727+ inputStream . eatSpace ( ) ;
57115728 // Parse command name.
57125729 var commandMatch = inputStream . match ( / ^ ( \w + | ! ! | @ @ | [ ! # & * < = > @ ~ ] ) / ) ;
57135730 if ( commandMatch ) {
@@ -5723,43 +5740,68 @@ export function initVim(CM) {
57235740 * @param {import("@codemirror/language").StringStream } inputStream
57245741 */
57255742 parseLineSpec_ ( cm , inputStream ) {
5726- var numberMatch = inputStream . match ( / ^ ( \d + ) / ) ;
5743+ var numberMatch = inputStream . match ( / ^ ( [ \d ] + ) / ) ;
57275744 if ( numberMatch ) {
5728- // Absolute line number plus offset (N+M or N-M) is probably a typo,
5729- // not something the user actually wanted. (NB: vim does allow this.)
5730- return parseInt ( numberMatch [ 1 ] , 10 ) - 1 ;
5745+ return this . parseLineSpecOffset_ ( cm , inputStream , parseInt ( numberMatch [ 1 ] , 10 ) - 1 ) ;
57315746 }
57325747 switch ( inputStream . next ( ) ) {
57335748 case '.' :
5734- return this . parseLineSpecOffset_ ( inputStream , cm . getCursor ( ) . line ) ;
5749+ return this . parseLineSpecOffset_ ( cm , inputStream , cm . getCursor ( ) . line ) ;
57355750 case '$' :
5736- return this . parseLineSpecOffset_ ( inputStream , cm . lastLine ( ) ) ;
5751+ return this . parseLineSpecOffset_ ( cm , inputStream , cm . lastLine ( ) ) ;
57375752 case '\'' :
57385753 var markName = inputStream . next ( ) || "" ;
57395754 var markPos = getMarkPos ( cm , cm . state . vim , markName ) ;
57405755 if ( ! markPos ) throw new Error ( 'Mark not set' ) ;
5741- return this . parseLineSpecOffset_ ( inputStream , markPos . line ) ;
5756+ return this . parseLineSpecOffset_ ( cm , inputStream , markPos . line ) ;
57425757 case '-' :
57435758 case '+' :
5759+ case '/' :
5760+ case '?' :
57445761 inputStream . backUp ( 1 ) ;
57455762 // Offset is relative to current line if not otherwise specified.
5746- return this . parseLineSpecOffset_ ( inputStream , cm . getCursor ( ) . line ) ;
5763+ return this . parseLineSpecOffset_ ( cm , inputStream , cm . getCursor ( ) . line ) ;
57475764 default :
57485765 inputStream . backUp ( 1 ) ;
57495766 return undefined ;
57505767 }
57515768 }
57525769 /**
5770+ * @param {CodeMirrorV } cm
57535771 * @param {string | import("@codemirror/language").StringStream } inputStream
57545772 * @param {number } line
57555773 */
5756- parseLineSpecOffset_ ( inputStream , line ) {
5757- var offsetMatch = inputStream . match ( / ^ ( [ + - ] ) ? ( \d + ) / ) ;
5758- if ( offsetMatch ) {
5759- var offset = parseInt ( offsetMatch [ 2 ] , 10 ) ;
5760- if ( offsetMatch [ 1 ] == "-" ) {
5761- line -= offset ;
5774+ parseLineSpecOffset_ ( cm , inputStream , line ) {
5775+ while ( true ) {
5776+ var offsetMatch = inputStream . match ( / ^ ( [ \/ \? ] | \\ [ \? \/ ] ) | ( [ + - ] ? ) ( \d * ) / )
5777+ if ( ! offsetMatch || ! offsetMatch [ 0 ] )
5778+ break ;
5779+
5780+ if ( offsetMatch [ 1 ] ) {
5781+ var queryString = "" ;
5782+ var forward = ! offsetMatch [ 1 ] . endsWith ( "?" ) ;
5783+ if ( offsetMatch [ 1 ] . length == 1 ) {
5784+ var queryMatch = inputStream . match ( forward ? / ^ ( [ ^ \/ \\ ] | \\ \/ ) * / : / ^ ( [ ^ \/ \? ] | \\ \? ) * / ) ;
5785+ inputStream . match ( forward ? / ^ \/ ? / : / ^ \? ? / ) ;
5786+ queryString = queryMatch && queryMatch [ 0 ] ;
5787+ }
5788+ if ( ! queryString ) {
5789+ queryString = vimGlobalState . registerController . getRegister ( '/' ) ?. toString ( ) || "" ;
5790+ }
5791+ var query = new RegExp ( queryString ) ;
5792+ var cursor = cm . getSearchCursor ( query , new Pos ( line + ( forward ? 1 : 0 ) , 0 ) ) ;
5793+ if ( forward ) {
5794+ cursor . findNext ( ) ;
5795+ } else {
5796+ cursor . findPrevious ( ) ;
5797+ }
5798+ var nextPos = cursor . from ( ) ;
5799+ if ( ! nextPos ) {
5800+ throw new Error ( "Pattern not found" + query ) ;
5801+ }
5802+ line = nextPos . line ;
57625803 } else {
5804+ var offset = parseInt ( offsetMatch [ 2 ] + ( offsetMatch [ 3 ] || '1' ) , 10 ) ;
57635805 line += offset ;
57645806 }
57655807 }
@@ -6365,13 +6407,40 @@ export function initVim(CM) {
63656407 nohlsearch : function ( cm ) {
63666408 clearSearchHighlight ( cm ) ;
63676409 } ,
6368- /** @arg {CodeMirrorV} cm */
6369- yank : function ( cm ) {
6370- var cur = copyCursor ( cm . getCursor ( ) ) ;
6371- var line = cur . line ;
6372- var lineText = cm . getLine ( line ) ;
6410+ /** @arg {CodeMirrorV} cm @arg {ExParams} params */
6411+ yank : function ( cm , params ) {
6412+ var line = params . selectionLine ;
6413+ var lineEnd = isNaN ( params . selectionLineEnd ) ? line : params . selectionLineEnd ;
6414+ if ( lineEnd < line ) {
6415+ var tmp = lineEnd ;
6416+ lineEnd = line ;
6417+ line = tmp ;
6418+ }
6419+ var text = cm . getRange ( new Pos ( line , 0 ) , new Pos ( lineEnd + 1 , 0 ) ) ;
6420+ var registerName = params . args && params . args [ 0 ] ? params . args [ 0 ] : '0' ;
63736421 vimGlobalState . registerController . pushText (
6374- '0' , 'yank' , lineText , true , true ) ;
6422+ registerName , 'yank' , text , true , false ) ;
6423+ showConfirm ( cm , ( lineEnd + 1 - line ) + ' lines yanked' + ( registerName ? ' into "' + registerName : '' ) , false , 1500 ) ;
6424+ } ,
6425+ /** @arg {CodeMirrorV} cm @arg {ExParams} params @arg {boolean} [matchIndent]*/
6426+ put : function ( cm , params , matchIndent ) {
6427+ var actionArgs = { after : true , isEdit : true , matchIndent : ! ! matchIndent , repeat : 1 , lineWise : true , registerName : '' } ;
6428+ var args = params . args || [ ] ;
6429+ if ( args [ 0 ] == "!" ) {
6430+ actionArgs . after = false ;
6431+ args . shift ( ) ;
6432+ }
6433+ if ( args [ 0 ] ) {
6434+ actionArgs . registerName = args [ 0 ] ;
6435+ }
6436+ var line = params . selectionLine ;
6437+ if ( line != undefined )
6438+ cm . setCursor ( new Pos ( line , 0 ) ) ;
6439+ actions . paste ( cm , actionArgs , cm . state . vim ) ;
6440+ } ,
6441+ /** @arg {CodeMirrorV} cm @arg {ExParams} params*/
6442+ iput : function ( cm , params ) {
6443+ this . put ( cm , params , true ) ;
63756444 } ,
63766445 /** @arg {CodeMirrorV} cm @arg {ExParams} params*/
63776446 delete : function ( cm , params ) {
0 commit comments