2019-07-28 14:57:52 +02:00
var Pos = CodeMirror . Pos ;
CodeMirror . Vim . suppressErrorLogging = true ;
var code = '' +
' wOrd1 (#%\n' +
' word3] \n' +
'aopop pop 0 1 2 3 4\n' +
' (a) [b] {c} \n' +
'int getchar(void) {\n' +
' static char buf[BUFSIZ];\n' +
' static char *bufp = buf;\n' +
' if (n == 0) { /* buffer is empty */\n' +
' n = read(0, buf, sizeof buf);\n' +
' bufp = buf;\n' +
' }\n' +
'\n' +
' return (--n >= 0) ? (unsigned char) *bufp++ : EOF;\n' +
' \n' +
'}\n' ;
var lines = ( function ( ) {
lineText = code . split ( '\n' ) ;
var ret = [ ] ;
for ( var i = 0 ; i < lineText . length ; i ++ ) {
ret [ i ] = {
line : i ,
length : lineText [ i ] . length ,
lineText : lineText [ i ] ,
textStart : /^\s*/ . exec ( lineText [ i ] ) [ 0 ] . length
} ;
}
return ret ;
} ) ( ) ;
var endOfDocument = makeCursor ( lines . length - 1 ,
lines [ lines . length - 1 ] . length ) ;
var wordLine = lines [ 0 ] ;
var bigWordLine = lines [ 1 ] ;
var charLine = lines [ 2 ] ;
var bracesLine = lines [ 3 ] ;
var seekBraceLine = lines [ 4 ] ;
2020-10-02 13:05:50 +02:00
var foldingStart = lines [ 7 ] ;
var foldingEnd = lines [ 11 ] ;
2019-07-28 14:57:52 +02:00
var word1 = {
start : new Pos ( wordLine . line , 1 ) ,
end : new Pos ( wordLine . line , 5 )
} ;
var word2 = {
start : new Pos ( wordLine . line , word1 . end . ch + 2 ) ,
end : new Pos ( wordLine . line , word1 . end . ch + 4 )
} ;
var word3 = {
start : new Pos ( bigWordLine . line , 1 ) ,
end : new Pos ( bigWordLine . line , 5 )
} ;
var bigWord1 = word1 ;
var bigWord2 = word2 ;
var bigWord3 = {
start : new Pos ( bigWordLine . line , 1 ) ,
end : new Pos ( bigWordLine . line , 7 )
} ;
var bigWord4 = {
start : new Pos ( bigWordLine . line , bigWord1 . end . ch + 3 ) ,
end : new Pos ( bigWordLine . line , bigWord1 . end . ch + 7 )
} ;
var oChars = [ new Pos ( charLine . line , 1 ) ,
new Pos ( charLine . line , 3 ) ,
new Pos ( charLine . line , 7 ) ] ;
var pChars = [ new Pos ( charLine . line , 2 ) ,
new Pos ( charLine . line , 4 ) ,
new Pos ( charLine . line , 6 ) ,
new Pos ( charLine . line , 8 ) ] ;
var numChars = [ new Pos ( charLine . line , 10 ) ,
new Pos ( charLine . line , 12 ) ,
new Pos ( charLine . line , 14 ) ,
new Pos ( charLine . line , 16 ) ,
new Pos ( charLine . line , 18 ) ] ;
var parens1 = {
start : new Pos ( bracesLine . line , 1 ) ,
end : new Pos ( bracesLine . line , 3 )
} ;
var squares1 = {
start : new Pos ( bracesLine . line , 5 ) ,
end : new Pos ( bracesLine . line , 7 )
} ;
var curlys1 = {
start : new Pos ( bracesLine . line , 9 ) ,
end : new Pos ( bracesLine . line , 11 )
} ;
var seekOutside = {
start : new Pos ( seekBraceLine . line , 1 ) ,
end : new Pos ( seekBraceLine . line , 16 )
} ;
var seekInside = {
start : new Pos ( seekBraceLine . line , 14 ) ,
end : new Pos ( seekBraceLine . line , 11 )
} ;
2020-10-02 13:05:50 +02:00
var foldingRangeDown = {
start : new Pos ( foldingStart . line , 3 ) ,
end : new Pos ( foldingEnd . line , 0 )
} ;
var foldingRangeUp = {
start : new Pos ( foldingEnd . line , 0 ) ,
end : new Pos ( foldingStart . line , 0 )
} ;
2019-07-28 14:57:52 +02:00
function copyCursor ( cur ) {
return new Pos ( cur . line , cur . ch ) ;
}
function forEach ( arr , func ) {
for ( var i = 0 ; i < arr . length ; i ++ ) {
func ( arr [ i ] , i , arr ) ;
}
}
function expectFail ( fn ) {
try {
fn ( ) ;
} catch ( expected ) {
return ;
} ;
throw new Error ( "Expected to throw an error" ) ;
}
function testVim ( name , run , opts , expectedFail ) {
var vimOpts = {
lineNumbers : true ,
vimMode : true ,
showCursorWhenSelecting : true ,
value : code
} ;
for ( var prop in opts ) {
if ( opts . hasOwnProperty ( prop ) ) {
vimOpts [ prop ] = opts [ prop ] ;
}
}
return test ( 'vim_' + name , function ( ) {
var place = document . getElementById ( "testground" ) ;
var cm = CodeMirror ( place , vimOpts ) ;
var vim = CodeMirror . Vim . maybeInitVimState _ ( cm ) ;
function doKeysFn ( cm ) {
return function ( args ) {
if ( args instanceof Array ) {
arguments = args ;
}
for ( var i = 0 ; i < arguments . length ; i ++ ) {
var result = CodeMirror . Vim . handleKey ( cm , arguments [ i ] ) ;
if ( ! result && cm . state . vim . insertMode ) {
cm . replaceSelections ( fillArray ( arguments [ i ] , cm . listSelections ( ) . length ) ) ;
}
}
}
}
function doInsertModeKeysFn ( cm ) {
return function ( args ) {
if ( args instanceof Array ) { arguments = args ; }
function executeHandler ( handler ) {
if ( typeof handler == 'string' ) {
CodeMirror . commands [ handler ] ( cm ) ;
} else {
handler ( cm ) ;
}
return true ;
}
for ( var i = 0 ; i < arguments . length ; i ++ ) {
var key = arguments [ i ] ;
// Find key in keymap and handle.
var handled = CodeMirror . lookupKey ( key , cm . getOption ( 'keyMap' ) , executeHandler , cm ) ;
// Record for insert mode.
if ( handled == "handled" && cm . state . vim . insertMode && arguments [ i ] != 'Esc' ) {
var lastChange = CodeMirror . Vim . getVimGlobalState _ ( ) . macroModeState . lastInsertModeChanges ;
if ( lastChange && ( key . indexOf ( 'Delete' ) != - 1 || key . indexOf ( 'Backspace' ) != - 1 ) ) {
lastChange . changes . push ( new CodeMirror . Vim . InsertModeKey ( key ) ) ;
}
}
}
}
}
function doExFn ( cm ) {
return function ( command ) {
cm . openDialog = helpers . fakeOpenDialog ( command ) ;
helpers . doKeys ( ':' ) ;
}
}
function assertCursorAtFn ( cm ) {
return function ( line , ch ) {
var pos ;
if ( ch == null && typeof line . line == 'number' ) {
pos = line ;
} else {
pos = makeCursor ( line , ch ) ;
}
eqCursorPos ( cm . getCursor ( ) , pos ) ;
}
}
function fakeOpenDialog ( result ) {
return function ( text , callback ) {
return callback ( result ) ;
}
}
function fakeOpenNotification ( matcher ) {
return function ( text ) {
matcher ( text ) ;
}
}
var helpers = {
doKeys : doKeysFn ( cm ) ,
// Warning: Only emulates keymap events, not character insertions. Use
// replaceRange to simulate character insertions.
// Keys are in CodeMirror format, NOT vim format.
doInsertModeKeys : doInsertModeKeysFn ( cm ) ,
doEx : doExFn ( cm ) ,
assertCursorAt : assertCursorAtFn ( cm ) ,
fakeOpenDialog : fakeOpenDialog ,
fakeOpenNotification : fakeOpenNotification ,
getRegisterController : function ( ) {
return CodeMirror . Vim . getRegisterController ( ) ;
}
}
CodeMirror . Vim . resetVimGlobalState _ ( ) ;
var successful = false ;
var savedOpenNotification = cm . openNotification ;
var savedOpenDialog = cm . openDialog ;
try {
run ( cm , vim , helpers ) ;
successful = true ;
} finally {
cm . openNotification = savedOpenNotification ;
cm . openDialog = savedOpenDialog ;
if ( ! successful || verbose ) {
place . style . visibility = "visible" ;
} else {
place . removeChild ( cm . getWrapperElement ( ) ) ;
}
}
} , expectedFail ) ;
} ;
testVim ( 'qq@q' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'q' , 'q' , 'l' , 'l' , 'q' ) ;
helpers . assertCursorAt ( 0 , 2 ) ;
helpers . doKeys ( '@' , 'q' ) ;
helpers . assertCursorAt ( 0 , 4 ) ;
} , { value : ' ' } ) ;
testVim ( '@@' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'q' , 'q' , 'l' , 'l' , 'q' ) ;
helpers . assertCursorAt ( 0 , 2 ) ;
helpers . doKeys ( '@' , 'q' ) ;
helpers . assertCursorAt ( 0 , 4 ) ;
helpers . doKeys ( '@' , '@' ) ;
helpers . assertCursorAt ( 0 , 6 ) ;
} , { value : ' ' } ) ;
var jumplistScene = '' +
'word\n' +
'(word)\n' +
'{word\n' +
'word.\n' +
'\n' +
'word search\n' +
'}word\n' +
'word\n' +
'word\n' ;
function testJumplist ( name , keys , endPos , startPos , dialog ) {
endPos = makeCursor ( endPos [ 0 ] , endPos [ 1 ] ) ;
startPos = makeCursor ( startPos [ 0 ] , startPos [ 1 ] ) ;
testVim ( name , function ( cm , vim , helpers ) {
CodeMirror . Vim . resetVimGlobalState _ ( ) ;
if ( dialog ) cm . openDialog = helpers . fakeOpenDialog ( 'word' ) ;
cm . setCursor ( startPos ) ;
helpers . doKeys . apply ( null , keys ) ;
helpers . assertCursorAt ( endPos ) ;
} , { value : jumplistScene } ) ;
}
testJumplist ( 'jumplist_H' , [ 'H' , '<C-o>' ] , [ 5 , 2 ] , [ 5 , 2 ] ) ;
testJumplist ( 'jumplist_M' , [ 'M' , '<C-o>' ] , [ 2 , 2 ] , [ 2 , 2 ] ) ;
testJumplist ( 'jumplist_L' , [ 'L' , '<C-o>' ] , [ 2 , 2 ] , [ 2 , 2 ] ) ;
testJumplist ( 'jumplist_[[' , [ '[' , '[' , '<C-o>' ] , [ 5 , 2 ] , [ 5 , 2 ] ) ;
testJumplist ( 'jumplist_]]' , [ ']' , ']' , '<C-o>' ] , [ 2 , 2 ] , [ 2 , 2 ] ) ;
testJumplist ( 'jumplist_G' , [ 'G' , '<C-o>' ] , [ 5 , 2 ] , [ 5 , 2 ] ) ;
testJumplist ( 'jumplist_gg' , [ 'g' , 'g' , '<C-o>' ] , [ 5 , 2 ] , [ 5 , 2 ] ) ;
testJumplist ( 'jumplist_%' , [ '%' , '<C-o>' ] , [ 1 , 5 ] , [ 1 , 5 ] ) ;
testJumplist ( 'jumplist_{' , [ '{' , '<C-o>' ] , [ 1 , 5 ] , [ 1 , 5 ] ) ;
testJumplist ( 'jumplist_}' , [ '}' , '<C-o>' ] , [ 1 , 5 ] , [ 1 , 5 ] ) ;
testJumplist ( 'jumplist_\'' , [ 'm' , 'a' , 'h' , '\'' , 'a' , 'h' , '<C-i>' ] , [ 1 , 0 ] , [ 1 , 5 ] ) ;
testJumplist ( 'jumplist_`' , [ 'm' , 'a' , 'h' , '`' , 'a' , 'h' , '<C-i>' ] , [ 1 , 5 ] , [ 1 , 5 ] ) ;
testJumplist ( 'jumplist_*_cachedCursor' , [ '*' , '<C-o>' ] , [ 1 , 3 ] , [ 1 , 3 ] ) ;
testJumplist ( 'jumplist_#_cachedCursor' , [ '#' , '<C-o>' ] , [ 1 , 3 ] , [ 1 , 3 ] ) ;
testJumplist ( 'jumplist_n' , [ '#' , 'n' , '<C-o>' ] , [ 1 , 1 ] , [ 2 , 3 ] ) ;
testJumplist ( 'jumplist_N' , [ '#' , 'N' , '<C-o>' ] , [ 1 , 1 ] , [ 2 , 3 ] ) ;
testJumplist ( 'jumplist_repeat_<c-o>' , [ '*' , '*' , '*' , '3' , '<C-o>' ] , [ 2 , 3 ] , [ 2 , 3 ] ) ;
testJumplist ( 'jumplist_repeat_<c-i>' , [ '*' , '*' , '*' , '3' , '<C-o>' , '2' , '<C-i>' ] , [ 5 , 0 ] , [ 2 , 3 ] ) ;
testJumplist ( 'jumplist_repeated_motion' , [ '3' , '*' , '<C-o>' ] , [ 2 , 3 ] , [ 2 , 3 ] ) ;
testJumplist ( 'jumplist_/' , [ '/' , '<C-o>' ] , [ 2 , 3 ] , [ 2 , 3 ] , 'dialog' ) ;
testJumplist ( 'jumplist_?' , [ '?' , '<C-o>' ] , [ 2 , 3 ] , [ 2 , 3 ] , 'dialog' ) ;
testJumplist ( 'jumplist_skip_deleted_mark<c-o>' ,
[ '*' , 'n' , 'n' , 'k' , 'd' , 'k' , '<C-o>' , '<C-o>' , '<C-o>' ] ,
[ 0 , 2 ] , [ 0 , 2 ] ) ;
testJumplist ( 'jumplist_skip_deleted_mark<c-i>' ,
[ '*' , 'n' , 'n' , 'k' , 'd' , 'k' , '<C-o>' , '<C-i>' , '<C-i>' ] ,
[ 1 , 0 ] , [ 0 , 2 ] ) ;
/ * *
* @ param name Name of the test
* @ param keys An array of keys or a string with a single key to simulate .
* @ param endPos The expected end position of the cursor .
* @ param startPos The position the cursor should start at , defaults to 0 , 0.
* /
function testMotion ( name , keys , endPos , startPos ) {
testVim ( name , function ( cm , vim , helpers ) {
if ( ! startPos ) {
startPos = new Pos ( 0 , 0 ) ;
}
cm . setCursor ( startPos ) ;
helpers . doKeys ( keys ) ;
helpers . assertCursorAt ( endPos ) ;
} ) ;
}
2020-10-02 13:05:50 +02:00
function testMotionWithFolding ( name , keys , endPos , startPos ) {
testVim ( name , function ( cm , vim , helpers ) {
cm . foldCode ( startPos ) ;
cm . foldCode ( endPos ) ;
cm . setCursor ( startPos ) ;
helpers . doKeys ( keys ) ;
helpers . assertCursorAt ( endPos )
} )
}
2019-07-28 14:57:52 +02:00
function makeCursor ( line , ch ) {
return new Pos ( line , ch ) ;
}
function offsetCursor ( cur , offsetLine , offsetCh ) {
return new Pos ( cur . line + offsetLine , cur . ch + offsetCh ) ;
}
// Motion tests
testMotion ( '|' , '|' , makeCursor ( 0 , 0 ) , makeCursor ( 0 , 4 ) ) ;
testMotion ( '|_repeat' , [ '3' , '|' ] , makeCursor ( 0 , 2 ) , makeCursor ( 0 , 4 ) ) ;
testMotion ( 'h' , 'h' , makeCursor ( 0 , 0 ) , word1 . start ) ;
testMotion ( 'h_repeat' , [ '3' , 'h' ] , offsetCursor ( word1 . end , 0 , - 3 ) , word1 . end ) ;
testMotion ( 'l' , 'l' , makeCursor ( 0 , 1 ) ) ;
testMotion ( 'l_repeat' , [ '2' , 'l' ] , makeCursor ( 0 , 2 ) ) ;
testMotion ( 'j' , 'j' , offsetCursor ( word1 . end , 1 , 0 ) , word1 . end ) ;
testMotion ( 'j_repeat' , [ '2' , 'j' ] , offsetCursor ( word1 . end , 2 , 0 ) , word1 . end ) ;
testMotion ( 'j_repeat_clip' , [ '1000' , 'j' ] , endOfDocument ) ;
testMotion ( 'k' , 'k' , offsetCursor ( word3 . end , - 1 , 0 ) , word3 . end ) ;
testMotion ( 'k_repeat' , [ '2' , 'k' ] , makeCursor ( 0 , 4 ) , makeCursor ( 2 , 4 ) ) ;
testMotion ( 'k_repeat_clip' , [ '1000' , 'k' ] , makeCursor ( 0 , 4 ) , makeCursor ( 2 , 4 ) ) ;
testMotion ( 'w' , 'w' , word1 . start ) ;
testMotion ( 'keepHPos' , [ '5' , 'j' , 'j' , '7' , 'k' ] , makeCursor ( 8 , 12 ) , makeCursor ( 12 , 12 ) ) ;
testMotion ( 'keepHPosEol' , [ '$' , '2' , 'j' ] , makeCursor ( 2 , 18 ) ) ;
testMotion ( 'w_multiple_newlines_no_space' , 'w' , makeCursor ( 12 , 2 ) , makeCursor ( 11 , 2 ) ) ;
testMotion ( 'w_multiple_newlines_with_space' , 'w' , makeCursor ( 14 , 0 ) , makeCursor ( 12 , 51 ) ) ;
testMotion ( 'w_repeat' , [ '2' , 'w' ] , word2 . start ) ;
testMotion ( 'w_wrap' , [ 'w' ] , word3 . start , word2 . start ) ;
testMotion ( 'w_endOfDocument' , 'w' , endOfDocument , endOfDocument ) ;
testMotion ( 'w_start_to_end' , [ '1000' , 'w' ] , endOfDocument , makeCursor ( 0 , 0 ) ) ;
testMotion ( 'W' , 'W' , bigWord1 . start ) ;
testMotion ( 'W_repeat' , [ '2' , 'W' ] , bigWord3 . start , bigWord1 . start ) ;
testMotion ( 'e' , 'e' , word1 . end ) ;
testMotion ( 'e_repeat' , [ '2' , 'e' ] , word2 . end ) ;
testMotion ( 'e_wrap' , 'e' , word3 . end , word2 . end ) ;
testMotion ( 'e_endOfDocument' , 'e' , endOfDocument , endOfDocument ) ;
testMotion ( 'e_start_to_end' , [ '1000' , 'e' ] , endOfDocument , makeCursor ( 0 , 0 ) ) ;
testMotion ( 'b' , 'b' , word3 . start , word3 . end ) ;
testMotion ( 'b_repeat' , [ '2' , 'b' ] , word2 . start , word3 . end ) ;
testMotion ( 'b_wrap' , 'b' , word2 . start , word3 . start ) ;
testMotion ( 'b_startOfDocument' , 'b' , makeCursor ( 0 , 0 ) , makeCursor ( 0 , 0 ) ) ;
testMotion ( 'b_end_to_start' , [ '1000' , 'b' ] , makeCursor ( 0 , 0 ) , endOfDocument ) ;
testMotion ( 'ge' , [ 'g' , 'e' ] , word2 . end , word3 . end ) ;
testMotion ( 'ge_repeat' , [ '2' , 'g' , 'e' ] , word1 . end , word3 . start ) ;
testMotion ( 'ge_wrap' , [ 'g' , 'e' ] , word2 . end , word3 . start ) ;
testMotion ( 'ge_startOfDocument' , [ 'g' , 'e' ] , makeCursor ( 0 , 0 ) ,
makeCursor ( 0 , 0 ) ) ;
testMotion ( 'ge_end_to_start' , [ '1000' , 'g' , 'e' ] , makeCursor ( 0 , 0 ) , endOfDocument ) ;
testMotion ( 'gg' , [ 'g' , 'g' ] , makeCursor ( lines [ 0 ] . line , lines [ 0 ] . textStart ) ,
makeCursor ( 3 , 1 ) ) ;
testMotion ( 'gg_repeat' , [ '3' , 'g' , 'g' ] ,
makeCursor ( lines [ 2 ] . line , lines [ 2 ] . textStart ) ) ;
testMotion ( 'G' , 'G' ,
makeCursor ( lines [ lines . length - 1 ] . line , lines [ lines . length - 1 ] . textStart ) ,
makeCursor ( 3 , 1 ) ) ;
testMotion ( 'G_repeat' , [ '3' , 'G' ] , makeCursor ( lines [ 2 ] . line ,
lines [ 2 ] . textStart ) ) ;
// TODO: Make the test code long enough to test Ctrl-F and Ctrl-B.
testMotion ( '0' , '0' , makeCursor ( 0 , 0 ) , makeCursor ( 0 , 8 ) ) ;
testMotion ( '^' , '^' , makeCursor ( 0 , lines [ 0 ] . textStart ) , makeCursor ( 0 , 8 ) ) ;
testMotion ( '+' , '+' , makeCursor ( 1 , lines [ 1 ] . textStart ) , makeCursor ( 0 , 8 ) ) ;
testMotion ( '-' , '-' , makeCursor ( 0 , lines [ 0 ] . textStart ) , makeCursor ( 1 , 4 ) ) ;
testMotion ( '_' , [ '6' , '_' ] , makeCursor ( 5 , lines [ 5 ] . textStart ) , makeCursor ( 0 , 8 ) ) ;
testMotion ( '$' , '$' , makeCursor ( 0 , lines [ 0 ] . length - 1 ) , makeCursor ( 0 , 1 ) ) ;
testMotion ( '$_repeat' , [ '2' , '$' ] , makeCursor ( 1 , lines [ 1 ] . length - 1 ) ,
makeCursor ( 0 , 3 ) ) ;
2020-10-02 13:05:50 +02:00
testMotion ( '$' , [ 'v' , '$' ] , makeCursor ( 0 , lines [ 0 ] . length ) , makeCursor ( 0 , 1 ) ) ;
2019-07-28 14:57:52 +02:00
testMotion ( 'f' , [ 'f' , 'p' ] , pChars [ 0 ] , makeCursor ( charLine . line , 0 ) ) ;
testMotion ( 'f_repeat' , [ '2' , 'f' , 'p' ] , pChars [ 2 ] , pChars [ 0 ] ) ;
testMotion ( 'f_num' , [ 'f' , '2' ] , numChars [ 2 ] , makeCursor ( charLine . line , 0 ) ) ;
testMotion ( 't' , [ 't' , 'p' ] , offsetCursor ( pChars [ 0 ] , 0 , - 1 ) ,
makeCursor ( charLine . line , 0 ) ) ;
testMotion ( 't_repeat' , [ '2' , 't' , 'p' ] , offsetCursor ( pChars [ 2 ] , 0 , - 1 ) ,
pChars [ 0 ] ) ;
testMotion ( 'F' , [ 'F' , 'p' ] , pChars [ 0 ] , pChars [ 1 ] ) ;
testMotion ( 'F_repeat' , [ '2' , 'F' , 'p' ] , pChars [ 0 ] , pChars [ 2 ] ) ;
testMotion ( 'T' , [ 'T' , 'p' ] , offsetCursor ( pChars [ 0 ] , 0 , 1 ) , pChars [ 1 ] ) ;
testMotion ( 'T_repeat' , [ '2' , 'T' , 'p' ] , offsetCursor ( pChars [ 0 ] , 0 , 1 ) , pChars [ 2 ] ) ;
testMotion ( '%_parens' , [ '%' ] , parens1 . end , parens1 . start ) ;
testMotion ( '%_squares' , [ '%' ] , squares1 . end , squares1 . start ) ;
testMotion ( '%_braces' , [ '%' ] , curlys1 . end , curlys1 . start ) ;
testMotion ( '%_seek_outside' , [ '%' ] , seekOutside . end , seekOutside . start ) ;
testMotion ( '%_seek_inside' , [ '%' ] , seekInside . end , seekInside . start ) ;
2020-10-02 13:05:50 +02:00
// Motion with folding tests
testMotionWithFolding ( 'j_with_folding' , 'j' , foldingRangeDown . end , foldingRangeDown . start ) ;
testMotionWithFolding ( 'k_with_folding' , 'k' , foldingRangeUp . end , foldingRangeUp . start ) ;
2019-07-28 14:57:52 +02:00
testVim ( '%_seek_skip' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( [ '%' ] ) ;
helpers . assertCursorAt ( 0 , 9 ) ;
} , { value : '01234"("()' } ) ;
testVim ( '%_skip_string' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( [ '%' ] ) ;
helpers . assertCursorAt ( 0 , 4 ) ;
cm . setCursor ( 0 , 2 ) ;
helpers . doKeys ( [ '%' ] ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
} , { value : '(")")' } ) ;
testVim ( '%_skip_comment' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( [ '%' ] ) ;
helpers . assertCursorAt ( 0 , 6 ) ;
cm . setCursor ( 0 , 3 ) ;
helpers . doKeys ( [ '%' ] ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
} , { value : '(/*)*/)' } ) ;
// Make sure that moving down after going to the end of a line always leaves you
// at the end of a line, but preserves the offset in other cases
testVim ( 'Changing lines after Eol operation' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( [ '$' ] ) ;
helpers . doKeys ( [ 'j' ] ) ;
// After moving to Eol and then down, we should be at Eol of line 2
helpers . assertCursorAt ( new Pos ( 1 , lines [ 1 ] . length - 1 ) ) ;
helpers . doKeys ( [ 'j' ] ) ;
// After moving down, we should be at Eol of line 3
helpers . assertCursorAt ( new Pos ( 2 , lines [ 2 ] . length - 1 ) ) ;
helpers . doKeys ( [ 'h' ] ) ;
helpers . doKeys ( [ 'j' ] ) ;
// After moving back one space and then down, since line 4 is shorter than line 2, we should
// be at Eol of line 2 - 1
helpers . assertCursorAt ( new Pos ( 3 , lines [ 3 ] . length - 1 ) ) ;
helpers . doKeys ( [ 'j' ] ) ;
helpers . doKeys ( [ 'j' ] ) ;
// After moving down again, since line 3 has enough characters, we should be back to the
// same place we were at on line 1
helpers . assertCursorAt ( new Pos ( 5 , lines [ 2 ] . length - 2 ) ) ;
} ) ;
//making sure gj and gk recover from clipping
testVim ( 'gj_gk_clipping' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( 'g' , 'j' , 'g' , 'j' ) ;
helpers . assertCursorAt ( 2 , 1 ) ;
helpers . doKeys ( 'g' , 'k' , 'g' , 'k' ) ;
helpers . assertCursorAt ( 0 , 1 ) ;
} , { value : 'line 1\n\nline 2' } ) ;
//testing a mix of j/k and gj/gk
testVim ( 'j_k_and_gj_gk' , function ( cm , vim , helpers ) {
cm . setSize ( 120 ) ;
cm . setCursor ( 0 , 0 ) ;
//go to the last character on the first line
helpers . doKeys ( '$' ) ;
//move up/down on the column within the wrapped line
//side-effect: cursor is not locked to eol anymore
helpers . doKeys ( 'g' , 'k' ) ;
var cur = cm . getCursor ( ) ;
eq ( cur . line , 0 ) ;
is ( ( cur . ch < 176 ) , 'gk didn\'t move cursor back (1)' ) ;
helpers . doKeys ( 'g' , 'j' ) ;
helpers . assertCursorAt ( 0 , 176 ) ;
//should move to character 177 on line 2 (j/k preserve character index within line)
helpers . doKeys ( 'j' ) ;
//due to different line wrapping, the cursor can be on a different screen-x now
//gj and gk preserve screen-x on movement, much like moveV
helpers . doKeys ( '3' , 'g' , 'k' ) ;
cur = cm . getCursor ( ) ;
eq ( cur . line , 1 ) ;
is ( ( cur . ch < 176 ) , 'gk didn\'t move cursor back (2)' ) ;
helpers . doKeys ( 'g' , 'j' , '2' , 'g' , 'j' ) ;
//should return to the same character-index
helpers . doKeys ( 'k' ) ;
helpers . assertCursorAt ( 0 , 176 ) ;
} , { lineWrapping : true , value : 'This line is intentially long to test movement of gj and gk over wrapped lines. I will start on the end of this line, then make a step up and back to set the origin for j and k.\nThis line is supposed to be even longer than the previous. I will jump here and make another wiggle with gj and gk, before I jump back to the line above. Both wiggles should not change my cursor\'s target character but both j/k and gj/gk change each other\'s reference position.' } ) ;
testVim ( 'gj_gk' , function ( cm , vim , helpers ) {
cm . setSize ( 120 ) ;
// Test top of document edge case.
cm . setCursor ( 0 , 4 ) ;
helpers . doKeys ( 'g' , 'j' ) ;
helpers . doKeys ( '10' , 'g' , 'k' ) ;
helpers . assertCursorAt ( 0 , 4 ) ;
// Test moving down preserves column position.
helpers . doKeys ( 'g' , 'j' ) ;
var pos1 = cm . getCursor ( ) ;
var expectedPos2 = new Pos ( 0 , ( pos1 . ch - 4 ) * 2 + 4 ) ;
helpers . doKeys ( 'g' , 'j' ) ;
helpers . assertCursorAt ( expectedPos2 ) ;
// Move to the last character
cm . setCursor ( 0 , 0 ) ;
// Move left to reset HSPos
helpers . doKeys ( 'h' ) ;
// Test bottom of document edge case.
helpers . doKeys ( '100' , 'g' , 'j' ) ;
var endingPos = cm . getCursor ( ) ;
is ( endingPos != 0 , 'gj should not be on wrapped line 0' ) ;
var topLeftCharCoords = cm . charCoords ( makeCursor ( 0 , 0 ) ) ;
var endingCharCoords = cm . charCoords ( endingPos ) ;
is ( topLeftCharCoords . left == endingCharCoords . left , 'gj should end up on column 0' ) ;
} , { lineNumbers : false , lineWrapping : true , value : 'Thislineisintentionallylongtotestmovementofgjandgkoverwrappedlines.' } ) ;
testVim ( '}' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '}' ) ;
helpers . assertCursorAt ( 1 , 0 ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '2' , '}' ) ;
helpers . assertCursorAt ( 4 , 0 ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '6' , '}' ) ;
helpers . assertCursorAt ( 5 , 0 ) ;
} , { value : 'a\n\nb\nc\n\nd' } ) ;
testVim ( '{' , function ( cm , vim , helpers ) {
cm . setCursor ( 5 , 0 ) ;
helpers . doKeys ( '{' ) ;
helpers . assertCursorAt ( 4 , 0 ) ;
cm . setCursor ( 5 , 0 ) ;
helpers . doKeys ( '2' , '{' ) ;
helpers . assertCursorAt ( 1 , 0 ) ;
cm . setCursor ( 5 , 0 ) ;
helpers . doKeys ( '6' , '{' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
} , { value : 'a\n\nb\nc\n\nd' } ) ;
testVim ( '(' , function ( cm , vim , helpers ) {
cm . setCursor ( 6 , 23 ) ;
helpers . doKeys ( '(' ) ;
helpers . assertCursorAt ( 6 , 14 ) ;
helpers . doKeys ( '2' , '(' ) ;
helpers . assertCursorAt ( 5 , 0 ) ;
helpers . doKeys ( '(' ) ;
helpers . assertCursorAt ( 4 , 0 ) ;
helpers . doKeys ( '(' ) ;
helpers . assertCursorAt ( 3 , 0 ) ;
helpers . doKeys ( '(' ) ;
helpers . assertCursorAt ( 2 , 0 ) ;
helpers . doKeys ( '(' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
helpers . doKeys ( '(' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
} , { value : 'sentence1.\n\n\nsentence2\n\nsentence3. sentence4\n sentence5? sentence6!' } ) ;
testVim ( ')' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '2' , ')' ) ;
helpers . assertCursorAt ( 3 , 0 ) ;
helpers . doKeys ( ')' ) ;
helpers . assertCursorAt ( 4 , 0 ) ;
helpers . doKeys ( ')' ) ;
helpers . assertCursorAt ( 5 , 0 ) ;
helpers . doKeys ( ')' ) ;
helpers . assertCursorAt ( 5 , 11 ) ;
helpers . doKeys ( ')' ) ;
helpers . assertCursorAt ( 6 , 14 ) ;
helpers . doKeys ( ')' ) ;
helpers . assertCursorAt ( 6 , 23 ) ;
helpers . doKeys ( ')' ) ;
helpers . assertCursorAt ( 6 , 23 ) ;
} , { value : 'sentence1.\n\n\nsentence2\n\nsentence3. sentence4\n sentence5? sentence6!' } ) ;
testVim ( 'paragraph_motions' , function ( cm , vim , helpers ) {
cm . setCursor ( 10 , 0 ) ;
helpers . doKeys ( '{' ) ;
helpers . assertCursorAt ( 4 , 0 ) ;
helpers . doKeys ( '{' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
helpers . doKeys ( '2' , '}' ) ;
helpers . assertCursorAt ( 7 , 0 ) ;
helpers . doKeys ( '2' , '}' ) ;
helpers . assertCursorAt ( 16 , 0 ) ;
cm . setCursor ( 9 , 0 ) ;
helpers . doKeys ( '}' ) ;
helpers . assertCursorAt ( 14 , 0 ) ;
cm . setCursor ( 6 , 0 ) ;
helpers . doKeys ( '}' ) ;
helpers . assertCursorAt ( 7 , 0 ) ;
// ip inside empty space
cm . setCursor ( 10 , 0 ) ;
helpers . doKeys ( 'v' , 'i' , 'p' ) ;
eqCursorPos ( Pos ( 7 , 0 ) , cm . getCursor ( 'anchor' ) ) ;
eqCursorPos ( Pos ( 12 , 0 ) , cm . getCursor ( 'head' ) ) ;
helpers . doKeys ( 'i' , 'p' ) ;
eqCursorPos ( Pos ( 7 , 0 ) , cm . getCursor ( 'anchor' ) ) ;
eqCursorPos ( Pos ( 13 , 1 ) , cm . getCursor ( 'head' ) ) ;
helpers . doKeys ( '2' , 'i' , 'p' ) ;
eqCursorPos ( Pos ( 7 , 0 ) , cm . getCursor ( 'anchor' ) ) ;
eqCursorPos ( Pos ( 16 , 1 ) , cm . getCursor ( 'head' ) ) ;
// should switch to visualLine mode
cm . setCursor ( 14 , 0 ) ;
helpers . doKeys ( '<Esc>' , 'v' , 'i' , 'p' ) ;
helpers . assertCursorAt ( 14 , 0 ) ;
cm . setCursor ( 14 , 0 ) ;
helpers . doKeys ( '<Esc>' , 'V' , 'i' , 'p' ) ;
eqCursorPos ( Pos ( 16 , 1 ) , cm . getCursor ( 'head' ) ) ;
// ap inside empty space
cm . setCursor ( 10 , 0 ) ;
helpers . doKeys ( '<Esc>' , 'v' , 'a' , 'p' ) ;
eqCursorPos ( Pos ( 7 , 0 ) , cm . getCursor ( 'anchor' ) ) ;
eqCursorPos ( Pos ( 13 , 1 ) , cm . getCursor ( 'head' ) ) ;
helpers . doKeys ( 'a' , 'p' ) ;
eqCursorPos ( Pos ( 7 , 0 ) , cm . getCursor ( 'anchor' ) ) ;
eqCursorPos ( Pos ( 16 , 1 ) , cm . getCursor ( 'head' ) ) ;
cm . setCursor ( 13 , 0 ) ;
helpers . doKeys ( 'v' , 'a' , 'p' ) ;
eqCursorPos ( Pos ( 13 , 0 ) , cm . getCursor ( 'anchor' ) ) ;
eqCursorPos ( Pos ( 14 , 0 ) , cm . getCursor ( 'head' ) ) ;
cm . setCursor ( 16 , 0 ) ;
helpers . doKeys ( 'v' , 'a' , 'p' ) ;
eqCursorPos ( Pos ( 14 , 0 ) , cm . getCursor ( 'anchor' ) ) ;
eqCursorPos ( Pos ( 16 , 1 ) , cm . getCursor ( 'head' ) ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'v' , 'a' , 'p' ) ;
eqCursorPos ( Pos ( 0 , 0 ) , cm . getCursor ( 'anchor' ) ) ;
eqCursorPos ( Pos ( 4 , 0 ) , cm . getCursor ( 'head' ) ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'd' , 'i' , 'p' ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( 'a\na\n' , register . toString ( ) ) ;
is ( register . linewise ) ;
helpers . doKeys ( '3' , 'j' , 'p' ) ;
helpers . doKeys ( 'y' , 'i' , 'p' ) ;
is ( register . linewise ) ;
eq ( 'b\na\na\nc\n' , register . toString ( ) ) ;
} , { value : 'a\na\n\n\n\nb\nc\n\n\n\n\n\n\nd\n\ne\nf' } ) ;
// Operator tests
testVim ( 'dl' , function ( cm , vim , helpers ) {
var curStart = makeCursor ( 0 , 0 ) ;
cm . setCursor ( curStart ) ;
helpers . doKeys ( 'd' , 'l' ) ;
eq ( 'word1 ' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( ' ' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
eqCursorPos ( curStart , cm . getCursor ( ) ) ;
} , { value : ' word1 ' } ) ;
testVim ( 'dl_eol' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 6 ) ;
helpers . doKeys ( 'd' , 'l' ) ;
eq ( ' word1' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( ' ' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
helpers . assertCursorAt ( 0 , 5 ) ;
} , { value : ' word1 ' } ) ;
testVim ( 'dl_repeat' , function ( cm , vim , helpers ) {
var curStart = makeCursor ( 0 , 0 ) ;
cm . setCursor ( curStart ) ;
helpers . doKeys ( '2' , 'd' , 'l' ) ;
eq ( 'ord1 ' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( ' w' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
eqCursorPos ( curStart , cm . getCursor ( ) ) ;
} , { value : ' word1 ' } ) ;
testVim ( 'dh' , function ( cm , vim , helpers ) {
var curStart = makeCursor ( 0 , 3 ) ;
cm . setCursor ( curStart ) ;
helpers . doKeys ( 'd' , 'h' ) ;
eq ( ' wrd1 ' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( 'o' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
eqCursorPos ( offsetCursor ( curStart , 0 , - 1 ) , cm . getCursor ( ) ) ;
} , { value : ' word1 ' } ) ;
testVim ( 'dj' , function ( cm , vim , helpers ) {
var curStart = makeCursor ( 0 , 3 ) ;
cm . setCursor ( curStart ) ;
helpers . doKeys ( 'd' , 'j' ) ;
eq ( ' word3' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( ' word1\nword2\n' , register . toString ( ) ) ;
is ( register . linewise ) ;
helpers . assertCursorAt ( 0 , 1 ) ;
} , { value : ' word1\nword2\n word3' } ) ;
testVim ( 'dj_end_of_document' , function ( cm , vim , helpers ) {
var curStart = makeCursor ( 0 , 3 ) ;
cm . setCursor ( curStart ) ;
helpers . doKeys ( 'd' , 'j' ) ;
eq ( '' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( ' word1 \n' , register . toString ( ) ) ;
is ( register . linewise ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
} , { value : ' word1 ' } ) ;
testVim ( 'dk' , function ( cm , vim , helpers ) {
var curStart = makeCursor ( 1 , 3 ) ;
cm . setCursor ( curStart ) ;
helpers . doKeys ( 'd' , 'k' ) ;
eq ( ' word3' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( ' word1\nword2\n' , register . toString ( ) ) ;
is ( register . linewise ) ;
helpers . assertCursorAt ( 0 , 1 ) ;
} , { value : ' word1\nword2\n word3' } ) ;
testVim ( 'dk_start_of_document' , function ( cm , vim , helpers ) {
var curStart = makeCursor ( 0 , 3 ) ;
cm . setCursor ( curStart ) ;
helpers . doKeys ( 'd' , 'k' ) ;
eq ( '' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( ' word1 \n' , register . toString ( ) ) ;
is ( register . linewise ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
} , { value : ' word1 ' } ) ;
testVim ( 'dw_space' , function ( cm , vim , helpers ) {
var curStart = makeCursor ( 0 , 0 ) ;
cm . setCursor ( curStart ) ;
helpers . doKeys ( 'd' , 'w' ) ;
eq ( 'word1 ' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( ' ' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
eqCursorPos ( curStart , cm . getCursor ( ) ) ;
} , { value : ' word1 ' } ) ;
testVim ( 'dw_word' , function ( cm , vim , helpers ) {
var curStart = makeCursor ( 0 , 1 ) ;
cm . setCursor ( curStart ) ;
helpers . doKeys ( 'd' , 'w' ) ;
eq ( ' word2' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( 'word1 ' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
eqCursorPos ( curStart , cm . getCursor ( ) ) ;
} , { value : ' word1 word2' } ) ;
testVim ( 'dw_unicode_word' , function ( cm , vim , helpers ) {
helpers . doKeys ( 'd' , 'w' ) ;
eq ( cm . getValue ( ) . length , 10 ) ;
helpers . doKeys ( 'd' , 'w' ) ;
eq ( cm . getValue ( ) . length , 6 ) ;
helpers . doKeys ( 'd' , 'w' ) ;
eq ( cm . getValue ( ) . length , 5 ) ;
helpers . doKeys ( 'd' , 'e' ) ;
eq ( cm . getValue ( ) . length , 2 ) ;
} , { value : ' \u0562\u0561\u0580\u0587\xbbe\xb5g ' } ) ;
testVim ( 'dw_only_word' , function ( cm , vim , helpers ) {
// Test that if there is only 1 word left, dw deletes till the end of the
// line.
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( 'd' , 'w' ) ;
eq ( ' ' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( 'word1 ' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
} , { value : ' word1 ' } ) ;
testVim ( 'dw_eol' , function ( cm , vim , helpers ) {
// Assert that dw does not delete the newline if last word to delete is at end
// of line.
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( 'd' , 'w' ) ;
eq ( ' \nword2' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( 'word1' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
} , { value : ' word1\nword2' } ) ;
testVim ( 'dw_eol_with_multiple_newlines' , function ( cm , vim , helpers ) {
// Assert that dw does not delete the newline if last word to delete is at end
// of line and it is followed by multiple newlines.
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( 'd' , 'w' ) ;
eq ( ' \n\nword2' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( 'word1' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
} , { value : ' word1\n\nword2' } ) ;
testVim ( 'dw_empty_line_followed_by_whitespace' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'd' , 'w' ) ;
eq ( ' \nword' , cm . getValue ( ) ) ;
} , { value : '\n \nword' } ) ;
testVim ( 'dw_empty_line_followed_by_word' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'd' , 'w' ) ;
eq ( 'word' , cm . getValue ( ) ) ;
} , { value : '\nword' } ) ;
testVim ( 'dw_empty_line_followed_by_empty_line' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'd' , 'w' ) ;
eq ( '\n' , cm . getValue ( ) ) ;
} , { value : '\n\n' } ) ;
testVim ( 'dw_whitespace_followed_by_whitespace' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'd' , 'w' ) ;
eq ( '\n \n' , cm . getValue ( ) ) ;
} , { value : ' \n \n' } ) ;
testVim ( 'dw_whitespace_followed_by_empty_line' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'd' , 'w' ) ;
eq ( '\n\n' , cm . getValue ( ) ) ;
} , { value : ' \n\n' } ) ;
testVim ( 'dw_word_whitespace_word' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'd' , 'w' ) ;
eq ( '\n \nword2' , cm . getValue ( ) ) ;
} , { value : 'word1\n \nword2' } )
testVim ( 'dw_end_of_document' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 2 ) ;
helpers . doKeys ( 'd' , 'w' ) ;
eq ( '\nab' , cm . getValue ( ) ) ;
} , { value : '\nabc' } ) ;
testVim ( 'dw_repeat' , function ( cm , vim , helpers ) {
// Assert that dw does delete newline if it should go to the next line, and
// that repeat works properly.
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( 'd' , '2' , 'w' ) ;
eq ( ' ' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( 'word1\nword2' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
} , { value : ' word1\nword2' } ) ;
testVim ( 'de_word_start_and_empty_lines' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'd' , 'e' ) ;
eq ( '\n\n' , cm . getValue ( ) ) ;
} , { value : 'word\n\n' } ) ;
testVim ( 'de_word_end_and_empty_lines' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 3 ) ;
helpers . doKeys ( 'd' , 'e' ) ;
eq ( 'wor' , cm . getValue ( ) ) ;
} , { value : 'word\n\n\n' } ) ;
testVim ( 'de_whitespace_and_empty_lines' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'd' , 'e' ) ;
eq ( '' , cm . getValue ( ) ) ;
} , { value : ' \n\n\n' } ) ;
testVim ( 'de_end_of_document' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 2 ) ;
helpers . doKeys ( 'd' , 'e' ) ;
eq ( '\nab' , cm . getValue ( ) ) ;
} , { value : '\nabc' } ) ;
testVim ( 'db_empty_lines' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 0 ) ;
helpers . doKeys ( 'd' , 'b' ) ;
eq ( '\n\n' , cm . getValue ( ) ) ;
} , { value : '\n\n\n' } ) ;
testVim ( 'db_word_start_and_empty_lines' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 0 ) ;
helpers . doKeys ( 'd' , 'b' ) ;
eq ( '\nword' , cm . getValue ( ) ) ;
} , { value : '\n\nword' } ) ;
testVim ( 'db_word_end_and_empty_lines' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 3 ) ;
helpers . doKeys ( 'd' , 'b' ) ;
eq ( '\n\nd' , cm . getValue ( ) ) ;
} , { value : '\n\nword' } ) ;
testVim ( 'db_whitespace_and_empty_lines' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 0 ) ;
helpers . doKeys ( 'd' , 'b' ) ;
eq ( '' , cm . getValue ( ) ) ;
} , { value : '\n \n' } ) ;
testVim ( 'db_start_of_document' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'd' , 'b' ) ;
eq ( 'abc\n' , cm . getValue ( ) ) ;
} , { value : 'abc\n' } ) ;
testVim ( 'dge_empty_lines' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 0 ) ;
helpers . doKeys ( 'd' , 'g' , 'e' ) ;
// Note: In real VIM the result should be '', but it's not quite consistent,
// since 2 newlines are deleted. But in the similar case of word\n\n, only
// 1 newline is deleted. We'll diverge from VIM's behavior since it's much
// easier this way.
eq ( '\n' , cm . getValue ( ) ) ;
} , { value : '\n\n' } ) ;
testVim ( 'dge_word_and_empty_lines' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 0 ) ;
helpers . doKeys ( 'd' , 'g' , 'e' ) ;
eq ( 'wor\n' , cm . getValue ( ) ) ;
} , { value : 'word\n\n' } ) ;
testVim ( 'dge_whitespace_and_empty_lines' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 0 ) ;
helpers . doKeys ( 'd' , 'g' , 'e' ) ;
eq ( '' , cm . getValue ( ) ) ;
} , { value : '\n \n' } ) ;
testVim ( 'dge_start_of_document' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'd' , 'g' , 'e' ) ;
eq ( 'bc\n' , cm . getValue ( ) ) ;
} , { value : 'abc\n' } ) ;
testVim ( 'd_inclusive' , function ( cm , vim , helpers ) {
// Assert that when inclusive is set, the character the cursor is on gets
// deleted too.
var curStart = makeCursor ( 0 , 1 ) ;
cm . setCursor ( curStart ) ;
helpers . doKeys ( 'd' , 'e' ) ;
eq ( ' ' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( 'word1' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
eqCursorPos ( curStart , cm . getCursor ( ) ) ;
} , { value : ' word1 ' } ) ;
testVim ( 'd_reverse' , function ( cm , vim , helpers ) {
// Test that deleting in reverse works.
cm . setCursor ( 1 , 0 ) ;
helpers . doKeys ( 'd' , 'b' ) ;
eq ( ' word2 ' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( 'word1\n' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
helpers . assertCursorAt ( 0 , 1 ) ;
} , { value : ' word1\nword2 ' } ) ;
testVim ( 'dd' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 3 ) ;
var expectedBuffer = cm . getRange ( new Pos ( 0 , 0 ) ,
new Pos ( 1 , 0 ) ) ;
var expectedLineCount = cm . lineCount ( ) - 1 ;
helpers . doKeys ( 'd' , 'd' ) ;
eq ( expectedLineCount , cm . lineCount ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( expectedBuffer , register . toString ( ) ) ;
is ( register . linewise ) ;
helpers . assertCursorAt ( 0 , lines [ 1 ] . textStart ) ;
} ) ;
testVim ( 'dd_prefix_repeat' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 3 ) ;
var expectedBuffer = cm . getRange ( new Pos ( 0 , 0 ) ,
new Pos ( 2 , 0 ) ) ;
var expectedLineCount = cm . lineCount ( ) - 2 ;
helpers . doKeys ( '2' , 'd' , 'd' ) ;
eq ( expectedLineCount , cm . lineCount ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( expectedBuffer , register . toString ( ) ) ;
is ( register . linewise ) ;
helpers . assertCursorAt ( 0 , lines [ 2 ] . textStart ) ;
} ) ;
testVim ( 'dd_motion_repeat' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 3 ) ;
var expectedBuffer = cm . getRange ( new Pos ( 0 , 0 ) ,
new Pos ( 2 , 0 ) ) ;
var expectedLineCount = cm . lineCount ( ) - 2 ;
helpers . doKeys ( 'd' , '2' , 'd' ) ;
eq ( expectedLineCount , cm . lineCount ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( expectedBuffer , register . toString ( ) ) ;
is ( register . linewise ) ;
helpers . assertCursorAt ( 0 , lines [ 2 ] . textStart ) ;
} ) ;
testVim ( 'dd_multiply_repeat' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 3 ) ;
var expectedBuffer = cm . getRange ( new Pos ( 0 , 0 ) ,
new Pos ( 6 , 0 ) ) ;
var expectedLineCount = cm . lineCount ( ) - 6 ;
helpers . doKeys ( '2' , 'd' , '3' , 'd' ) ;
eq ( expectedLineCount , cm . lineCount ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( expectedBuffer , register . toString ( ) ) ;
is ( register . linewise ) ;
helpers . assertCursorAt ( 0 , lines [ 6 ] . textStart ) ;
} ) ;
testVim ( 'dd_lastline' , function ( cm , vim , helpers ) {
cm . setCursor ( cm . lineCount ( ) , 0 ) ;
var expectedLineCount = cm . lineCount ( ) - 1 ;
helpers . doKeys ( 'd' , 'd' ) ;
eq ( expectedLineCount , cm . lineCount ( ) ) ;
helpers . assertCursorAt ( cm . lineCount ( ) - 1 , 0 ) ;
} ) ;
testVim ( 'dd_only_line' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
var expectedRegister = cm . getValue ( ) + "\n" ;
helpers . doKeys ( 'd' , 'd' ) ;
eq ( 1 , cm . lineCount ( ) ) ;
eq ( '' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( expectedRegister , register . toString ( ) ) ;
} , { value : "thisistheonlyline" } ) ;
// Yank commands should behave the exact same as d commands, expect that nothing
// gets deleted.
testVim ( 'yw_repeat' , function ( cm , vim , helpers ) {
// Assert that yw does yank newline if it should go to the next line, and
// that repeat works properly.
var curStart = makeCursor ( 0 , 1 ) ;
cm . setCursor ( curStart ) ;
helpers . doKeys ( 'y' , '2' , 'w' ) ;
eq ( ' word1\nword2' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( 'word1\nword2' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
eqCursorPos ( curStart , cm . getCursor ( ) ) ;
} , { value : ' word1\nword2' } ) ;
testVim ( 'yy_multiply_repeat' , function ( cm , vim , helpers ) {
var curStart = makeCursor ( 0 , 3 ) ;
cm . setCursor ( curStart ) ;
var expectedBuffer = cm . getRange ( new Pos ( 0 , 0 ) ,
new Pos ( 6 , 0 ) ) ;
var expectedLineCount = cm . lineCount ( ) ;
helpers . doKeys ( '2' , 'y' , '3' , 'y' ) ;
eq ( expectedLineCount , cm . lineCount ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( expectedBuffer , register . toString ( ) ) ;
is ( register . linewise ) ;
eqCursorPos ( curStart , cm . getCursor ( ) ) ;
} ) ;
testVim ( '2dd_blank_P' , function ( cm , vim , helpers ) {
helpers . doKeys ( '2' , 'd' , 'd' , 'P' ) ;
eq ( '\na\n\n' , cm . getValue ( ) ) ;
} , { value : '\na\n\n' } ) ;
// Change commands behave like d commands except that it also enters insert
// mode. In addition, when the change is linewise, an additional newline is
// inserted so that insert mode starts on that line.
testVim ( 'cw' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'c' , '2' , 'w' ) ;
eq ( ' word3' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
} , { value : 'word1 word2 word3' } ) ;
testVim ( 'cw_repeat' , function ( cm , vim , helpers ) {
// Assert that cw does delete newline if it should go to the next line, and
// that repeat works properly.
var curStart = makeCursor ( 0 , 1 ) ;
cm . setCursor ( curStart ) ;
helpers . doKeys ( 'c' , '2' , 'w' ) ;
eq ( ' ' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( 'word1\nword2' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
eqCursorPos ( curStart , cm . getCursor ( ) ) ;
eq ( 'vim-insert' , cm . getOption ( 'keyMap' ) ) ;
} , { value : ' word1\nword2' } ) ;
testVim ( 'cc_multiply_repeat' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 3 ) ;
var expectedBuffer = cm . getRange ( new Pos ( 0 , 0 ) ,
new Pos ( 6 , 0 ) ) ;
var expectedLineCount = cm . lineCount ( ) - 5 ;
helpers . doKeys ( '2' , 'c' , '3' , 'c' ) ;
eq ( expectedLineCount , cm . lineCount ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( expectedBuffer , register . toString ( ) ) ;
is ( register . linewise ) ;
eq ( 'vim-insert' , cm . getOption ( 'keyMap' ) ) ;
} ) ;
testVim ( 'ct' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( 'c' , 't' , 'w' ) ;
eq ( ' word1 word3' , cm . getValue ( ) ) ;
helpers . doKeys ( '<Esc>' , 'c' , '|' ) ;
eq ( ' word3' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
helpers . doKeys ( '<Esc>' , '2' , 'u' , 'w' , 'h' ) ;
helpers . doKeys ( 'c' , '2' , 'g' , 'e' ) ;
eq ( ' wordword3' , cm . getValue ( ) ) ;
} , { value : ' word1 word2 word3' } ) ;
testVim ( 'cc_should_not_append_to_document' , function ( cm , vim , helpers ) {
var expectedLineCount = cm . lineCount ( ) ;
cm . setCursor ( cm . lastLine ( ) , 0 ) ;
helpers . doKeys ( 'c' , 'c' ) ;
eq ( expectedLineCount , cm . lineCount ( ) ) ;
} ) ;
function fillArray ( val , times ) {
var arr = [ ] ;
for ( var i = 0 ; i < times ; i ++ ) {
arr . push ( val ) ;
}
return arr ;
}
testVim ( 'c_visual_block' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( '<C-v>' , '2' , 'j' , 'l' , 'l' , 'l' , 'c' ) ;
helpers . doKeys ( 'hello' ) ;
eq ( '1hello\n5hello\nahellofg' , cm . getValue ( ) ) ;
helpers . doKeys ( '<Esc>' ) ;
cm . setCursor ( 2 , 3 ) ;
helpers . doKeys ( '<C-v>' , '2' , 'k' , 'h' , 'C' ) ;
helpers . doKeys ( 'world' ) ;
eq ( '1hworld\n5hworld\nahworld' , cm . getValue ( ) ) ;
} , { value : '1234\n5678\nabcdefg' } ) ;
testVim ( 'c_visual_block_replay' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( '<C-v>' , '2' , 'j' , 'l' , 'c' ) ;
helpers . doKeys ( 'fo' ) ;
eq ( '1fo4\n5fo8\nafodefg' , cm . getValue ( ) ) ;
helpers . doKeys ( '<Esc>' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '.' ) ;
eq ( 'foo4\nfoo8\nfoodefg' , cm . getValue ( ) ) ;
} , { value : '1234\n5678\nabcdefg' } ) ;
testVim ( 'I_visual_block_replay' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 2 ) ;
helpers . doKeys ( '<C-v>' , '2' , 'j' , 'l' , 'I' ) ;
helpers . doKeys ( '+-' )
eq ( '12+-34\n56+-78\nab+-cdefg\nxyz' , cm . getValue ( ) ) ;
helpers . doKeys ( '<Esc>' ) ;
// ensure that repeat location doesn't depend on last selection
cm . setCursor ( 3 , 2 ) ;
helpers . doKeys ( 'g' , 'v' )
eq ( "+-34\n+-78\n+-cd" , cm . getSelection ( ) )
cm . setCursor ( 0 , 3 ) ;
helpers . doKeys ( '<C-v>' , '1' , 'j' , '2' , 'l' ) ;
eq ( "-34\n-78" , cm . getSelection ( ) ) ;
cm . setCursor ( 0 , 0 ) ;
eq ( "" , cm . getSelection ( ) ) ;
helpers . doKeys ( 'g' , 'v' ) ;
eq ( "-34\n-78" , cm . getSelection ( ) ) ;
cm . setCursor ( 1 , 1 ) ;
helpers . doKeys ( '.' ) ;
eq ( '12+-34\n5+-6+-78\na+-b+-cdefg\nx+-yz' , cm . getValue ( ) ) ;
} , { value : '1234\n5678\nabcdefg\nxyz' } ) ;
testVim ( 'd_visual_block' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( '<C-v>' , '2' , 'j' , 'l' , 'l' , 'l' , 'd' ) ;
eq ( '1\n5\nafg' , cm . getValue ( ) ) ;
} , { value : '1234\n5678\nabcdefg' } ) ;
testVim ( 'D_visual_block' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( '<C-v>' , '2' , 'j' , 'l' , 'D' ) ;
eq ( '1\n5\na' , cm . getValue ( ) ) ;
} , { value : '1234\n5678\nabcdefg' } ) ;
testVim ( 's_visual_block' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( '<C-v>' , '2' , 'j' , 'l' , 'l' , 'l' , 's' ) ;
helpers . doKeys ( 'hello{' ) ;
eq ( '1hello{\n5hello{\nahello{fg\n' , cm . getValue ( ) ) ;
helpers . doKeys ( '<Esc>' ) ;
cm . setCursor ( 2 , 3 ) ;
helpers . doKeys ( '<C-v>' , '1' , 'k' , 'h' , 'S' ) ;
helpers . doKeys ( 'world' ) ;
eq ( '1hello{\n world\n' , cm . getValue ( ) ) ;
} , { value : '1234\n5678\nabcdefg\n' } ) ;
2020-10-02 13:05:50 +02:00
// Test mode change event. It should only fire once per mode transition.
testVim ( 'on_mode_change' , function ( cm , vim , helpers ) {
var modeHist = [ ] ;
function callback ( arg ) {
var subMode = arg . subMode ? ':' + arg . subMode : '' ;
modeHist . push ( arg . mode + subMode ) ;
}
helpers . doKeys ( '<Esc>' , '<Esc>' ) ;
cm . on ( 'vim-mode-change' , callback ) ;
function test ( key , mode ) {
modeHist . length = 0 ;
helpers . doKeys ( key ) ;
eq ( modeHist . join ( ';' ) , mode ) ;
}
test ( 'v' , 'visual' ) ;
test ( 'c' , 'insert' ) ;
test ( '<Esc>' , 'normal' ) ;
test ( '<C-v>' , 'visual:blockwise' ) ;
test ( 'I' , 'insert' ) ;
test ( '<Esc>' , 'normal' ) ;
test ( 'R' , 'replace' ) ;
test ( 'x' , '' ) ;
test ( '<C-[>' , 'normal' ) ;
test ( 'v' , 'visual' ) ;
test ( 'V' , 'visual:linewise' ) ;
test ( '<C-v>' , 'visual:blockwise' ) ;
test ( 'v' , 'visual' ) ;
test ( '<C-c>' , 'normal' ) ;
test ( 'a' , 'insert' ) ;
test ( '<Esc>' , 'normal' ) ;
test ( 'v' , 'visual' ) ;
test ( ':' , '' ) ; // Event for Command-line mode not implemented.
test ( 'y' , 'normal' ) ;
} ) ;
2019-07-28 14:57:52 +02:00
// Swapcase commands edit in place and do not modify registers.
testVim ( 'g~w_repeat' , function ( cm , vim , helpers ) {
// Assert that dw does delete newline if it should go to the next line, and
// that repeat works properly.
var curStart = makeCursor ( 0 , 1 ) ;
cm . setCursor ( curStart ) ;
helpers . doKeys ( 'g' , '~' , '2' , 'w' ) ;
eq ( ' WORD1\nWORD2' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( '' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
eqCursorPos ( curStart , cm . getCursor ( ) ) ;
} , { value : ' word1\nword2' } ) ;
testVim ( 'g~g~' , function ( cm , vim , helpers ) {
var curStart = makeCursor ( 0 , 3 ) ;
cm . setCursor ( curStart ) ;
var expectedLineCount = cm . lineCount ( ) ;
var expectedValue = cm . getValue ( ) . toUpperCase ( ) ;
helpers . doKeys ( '2' , 'g' , '~' , '3' , 'g' , '~' ) ;
eq ( expectedValue , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( '' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
eqCursorPos ( curStart , cm . getCursor ( ) ) ;
} , { value : ' word1\nword2\nword3\nword4\nword5\nword6' } ) ;
testVim ( 'gu_and_gU' , function ( cm , vim , helpers ) {
var curStart = makeCursor ( 0 , 7 ) ;
var value = cm . getValue ( ) ;
cm . setCursor ( curStart ) ;
helpers . doKeys ( '2' , 'g' , 'U' , 'w' ) ;
eq ( cm . getValue ( ) , 'wa wb xX WC wd' ) ;
eqCursorPos ( curStart , cm . getCursor ( ) ) ;
helpers . doKeys ( '2' , 'g' , 'u' , 'w' ) ;
eq ( cm . getValue ( ) , value ) ;
helpers . doKeys ( '2' , 'g' , 'U' , 'B' ) ;
eq ( cm . getValue ( ) , 'wa WB Xx wc wd' ) ;
eqCursorPos ( makeCursor ( 0 , 3 ) , cm . getCursor ( ) ) ;
cm . setCursor ( makeCursor ( 0 , 4 ) ) ;
helpers . doKeys ( 'g' , 'u' , 'i' , 'w' ) ;
eq ( cm . getValue ( ) , 'wa wb Xx wc wd' ) ;
eqCursorPos ( makeCursor ( 0 , 3 ) , cm . getCursor ( ) ) ;
// TODO: support gUgU guu
// eqCursorPos(makeCursor(0, 0), cm.getCursor());
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( '' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
} , { value : 'wa wb xx wc wd' } ) ;
testVim ( 'visual_block_~' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 1 ) ;
helpers . doKeys ( '<C-v>' , 'l' , 'l' , 'j' , '~' ) ;
helpers . assertCursorAt ( 1 , 1 ) ;
eq ( 'hello\nwoRLd\naBCDe' , cm . getValue ( ) ) ;
cm . setCursor ( 2 , 0 ) ;
helpers . doKeys ( 'v' , 'l' , 'l' , '~' ) ;
helpers . assertCursorAt ( 2 , 0 ) ;
eq ( 'hello\nwoRLd\nAbcDe' , cm . getValue ( ) ) ;
} , { value : 'hello\nwOrld\nabcde' } ) ;
testVim ( '._swapCase_visualBlock' , function ( cm , vim , helpers ) {
helpers . doKeys ( '<C-v>' , 'j' , 'j' , 'l' , '~' ) ;
cm . setCursor ( 0 , 3 ) ;
helpers . doKeys ( '.' ) ;
eq ( 'HelLO\nWorLd\nAbcdE' , cm . getValue ( ) ) ;
} , { value : 'hEllo\nwOrlD\naBcDe' } ) ;
testVim ( '._delete_visualBlock' , function ( cm , vim , helpers ) {
helpers . doKeys ( '<C-v>' , 'j' , 'x' ) ;
eq ( 'ive\ne\nsome\nsugar' , cm . getValue ( ) ) ;
helpers . doKeys ( '.' ) ;
eq ( 've\n\nsome\nsugar' , cm . getValue ( ) ) ;
helpers . doKeys ( 'j' , 'j' , '.' ) ;
eq ( 've\n\nome\nugar' , cm . getValue ( ) ) ;
helpers . doKeys ( 'u' , '<C-r>' , '.' ) ;
eq ( 've\n\nme\ngar' , cm . getValue ( ) ) ;
} , { value : 'give\nme\nsome\nsugar' } ) ;
testVim ( '>{motion}' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 3 ) ;
var expectedLineCount = cm . lineCount ( ) ;
var expectedValue = ' word1\n word2\nword3 ' ;
helpers . doKeys ( '>' , 'k' ) ;
eq ( expectedValue , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( '' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
helpers . assertCursorAt ( 0 , 3 ) ;
} , { value : ' word1\nword2\nword3 ' , indentUnit : 2 } ) ;
testVim ( '>>' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 3 ) ;
var expectedLineCount = cm . lineCount ( ) ;
var expectedValue = ' word1\n word2\nword3 ' ;
helpers . doKeys ( '2' , '>' , '>' ) ;
eq ( expectedValue , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( '' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
helpers . assertCursorAt ( 0 , 3 ) ;
} , { value : ' word1\nword2\nword3 ' , indentUnit : 2 } ) ;
testVim ( '<{motion}' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 3 ) ;
var expectedLineCount = cm . lineCount ( ) ;
var expectedValue = ' word1\nword2\nword3 ' ;
helpers . doKeys ( '<' , 'k' ) ;
eq ( expectedValue , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( '' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
helpers . assertCursorAt ( 0 , 1 ) ;
} , { value : ' word1\n word2\nword3 ' , indentUnit : 2 } ) ;
testVim ( '<<' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 3 ) ;
var expectedLineCount = cm . lineCount ( ) ;
var expectedValue = ' word1\nword2\nword3 ' ;
helpers . doKeys ( '2' , '<' , '<' ) ;
eq ( expectedValue , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( '' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
helpers . assertCursorAt ( 0 , 1 ) ;
} , { value : ' word1\n word2\nword3 ' , indentUnit : 2 } ) ;
testVim ( '=' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 3 ) ;
helpers . doKeys ( '<C-v>' , 'j' , 'j' ) ;
var expectedValue = 'word1\nword2\nword3' ;
helpers . doKeys ( '=' ) ;
eq ( expectedValue , cm . getValue ( ) ) ;
} , { value : ' word1\n word2\n word3' , indentUnit : 2 } ) ;
2020-10-02 13:05:50 +02:00
// Edit tests - configureCm is an optional argument that gives caller
// access to the cm object.
function testEdit ( name , before , pos , edit , after , configureCm ) {
2019-07-28 14:57:52 +02:00
return testVim ( name , function ( cm , vim , helpers ) {
2020-10-02 13:05:50 +02:00
if ( configureCm ) {
configureCm ( cm ) ;
}
2019-07-28 14:57:52 +02:00
var ch = before . search ( pos )
var line = before . substring ( 0 , ch ) . split ( '\n' ) . length - 1 ;
if ( line ) {
ch = before . substring ( 0 , ch ) . split ( '\n' ) . pop ( ) . length ;
}
cm . setCursor ( line , ch ) ;
helpers . doKeys . apply ( this , edit . split ( '' ) ) ;
eq ( after , cm . getValue ( ) ) ;
} , { value : before } ) ;
}
// These Delete tests effectively cover word-wise Change, Visual & Yank.
// Tabs are used as differentiated whitespace to catch edge cases.
// Normal word:
testEdit ( 'diw_mid_spc' , 'foo \tbAr\t baz' , /A/ , 'diw' , 'foo \t\t baz' ) ;
testEdit ( 'daw_mid_spc' , 'foo \tbAr\t baz' , /A/ , 'daw' , 'foo \tbaz' ) ;
testEdit ( 'diw_mid_punct' , 'foo \tbAr.\t baz' , /A/ , 'diw' , 'foo \t.\t baz' ) ;
testEdit ( 'daw_mid_punct' , 'foo \tbAr.\t baz' , /A/ , 'daw' , 'foo.\t baz' ) ;
testEdit ( 'diw_mid_punct2' , 'foo \t,bAr.\t baz' , /A/ , 'diw' , 'foo \t,.\t baz' ) ;
testEdit ( 'daw_mid_punct2' , 'foo \t,bAr.\t baz' , /A/ , 'daw' , 'foo \t,.\t baz' ) ;
testEdit ( 'diw_start_spc' , 'bAr \tbaz' , /A/ , 'diw' , ' \tbaz' ) ;
testEdit ( 'daw_start_spc' , 'bAr \tbaz' , /A/ , 'daw' , 'baz' ) ;
testEdit ( 'diw_start_punct' , 'bAr. \tbaz' , /A/ , 'diw' , '. \tbaz' ) ;
testEdit ( 'daw_start_punct' , 'bAr. \tbaz' , /A/ , 'daw' , '. \tbaz' ) ;
testEdit ( 'diw_end_spc' , 'foo \tbAr' , /A/ , 'diw' , 'foo \t' ) ;
testEdit ( 'daw_end_spc' , 'foo \tbAr' , /A/ , 'daw' , 'foo' ) ;
testEdit ( 'diw_end_punct' , 'foo \tbAr.' , /A/ , 'diw' , 'foo \t.' ) ;
testEdit ( 'daw_end_punct' , 'foo \tbAr.' , /A/ , 'daw' , 'foo.' ) ;
// Big word:
testEdit ( 'diW_mid_spc' , 'foo \tbAr\t baz' , /A/ , 'diW' , 'foo \t\t baz' ) ;
testEdit ( 'daW_mid_spc' , 'foo \tbAr\t baz' , /A/ , 'daW' , 'foo \tbaz' ) ;
testEdit ( 'diW_mid_punct' , 'foo \tbAr.\t baz' , /A/ , 'diW' , 'foo \t\t baz' ) ;
testEdit ( 'daW_mid_punct' , 'foo \tbAr.\t baz' , /A/ , 'daW' , 'foo \tbaz' ) ;
testEdit ( 'diW_mid_punct2' , 'foo \t,bAr.\t baz' , /A/ , 'diW' , 'foo \t\t baz' ) ;
testEdit ( 'daW_mid_punct2' , 'foo \t,bAr.\t baz' , /A/ , 'daW' , 'foo \tbaz' ) ;
testEdit ( 'diW_start_spc' , 'bAr\t baz' , /A/ , 'diW' , '\t baz' ) ;
testEdit ( 'daW_start_spc' , 'bAr\t baz' , /A/ , 'daW' , 'baz' ) ;
testEdit ( 'diW_start_punct' , 'bAr.\t baz' , /A/ , 'diW' , '\t baz' ) ;
testEdit ( 'daW_start_punct' , 'bAr.\t baz' , /A/ , 'daW' , 'baz' ) ;
testEdit ( 'diW_end_spc' , 'foo \tbAr' , /A/ , 'diW' , 'foo \t' ) ;
testEdit ( 'daW_end_spc' , 'foo \tbAr' , /A/ , 'daW' , 'foo' ) ;
testEdit ( 'diW_end_punct' , 'foo \tbAr.' , /A/ , 'diW' , 'foo \t' ) ;
testEdit ( 'daW_end_punct' , 'foo \tbAr.' , /A/ , 'daW' , 'foo' ) ;
// Deleting text objects
// Open and close on same line
testEdit ( 'di(_open_spc' , 'foo (bAr) baz' , /\(/ , 'di(' , 'foo () baz' ) ;
testEdit ( 'di)_open_spc' , 'foo (bAr) baz' , /\(/ , 'di)' , 'foo () baz' ) ;
testEdit ( 'dib_open_spc' , 'foo (bAr) baz' , /\(/ , 'dib' , 'foo () baz' ) ;
testEdit ( 'da(_open_spc' , 'foo (bAr) baz' , /\(/ , 'da(' , 'foo baz' ) ;
testEdit ( 'da)_open_spc' , 'foo (bAr) baz' , /\(/ , 'da)' , 'foo baz' ) ;
testEdit ( 'di(_middle_spc' , 'foo (bAr) baz' , /A/ , 'di(' , 'foo () baz' ) ;
testEdit ( 'di)_middle_spc' , 'foo (bAr) baz' , /A/ , 'di)' , 'foo () baz' ) ;
testEdit ( 'da(_middle_spc' , 'foo (bAr) baz' , /A/ , 'da(' , 'foo baz' ) ;
testEdit ( 'da)_middle_spc' , 'foo (bAr) baz' , /A/ , 'da)' , 'foo baz' ) ;
testEdit ( 'di(_close_spc' , 'foo (bAr) baz' , /\)/ , 'di(' , 'foo () baz' ) ;
testEdit ( 'di)_close_spc' , 'foo (bAr) baz' , /\)/ , 'di)' , 'foo () baz' ) ;
testEdit ( 'da(_close_spc' , 'foo (bAr) baz' , /\)/ , 'da(' , 'foo baz' ) ;
testEdit ( 'da)_close_spc' , 'foo (bAr) baz' , /\)/ , 'da)' , 'foo baz' ) ;
testEdit ( 'di`' , 'foo `bAr` baz' , /`/ , 'di`' , 'foo `` baz' ) ;
testEdit ( 'di>' , 'foo <bAr> baz' , /</ , 'di>' , 'foo <> baz' ) ;
testEdit ( 'da<' , 'foo <bAr> baz' , /</ , 'da<' , 'foo baz' ) ;
// delete around and inner b.
testEdit ( 'dab_on_(_should_delete_around_()block' , 'o( in(abc) )' , /\(a/ , 'dab' , 'o( in )' ) ;
// delete around and inner B.
testEdit ( 'daB_on_{_should_delete_around_{}block' , 'o{ in{abc} }' , /{a/ , 'daB' , 'o{ in }' ) ;
testEdit ( 'diB_on_{_should_delete_inner_{}block' , 'o{ in{abc} }' , /{a/ , 'diB' , 'o{ in{} }' ) ;
testEdit ( 'da{_on_{_should_delete_inner_block' , 'o{ in{abc} }' , /{a/ , 'da{' , 'o{ in }' ) ;
testEdit ( 'di[_on_(_should_not_delete' , 'foo (bAr) baz' , /\(/ , 'di[' , 'foo (bAr) baz' ) ;
testEdit ( 'di[_on_)_should_not_delete' , 'foo (bAr) baz' , /\)/ , 'di[' , 'foo (bAr) baz' ) ;
testEdit ( 'da[_on_(_should_not_delete' , 'foo (bAr) baz' , /\(/ , 'da[' , 'foo (bAr) baz' ) ;
testEdit ( 'da[_on_)_should_not_delete' , 'foo (bAr) baz' , /\)/ , 'da[' , 'foo (bAr) baz' ) ;
testMotion ( 'di(_outside_should_stay' , [ 'd' , 'i' , '(' ] , new Pos ( 0 , 0 ) , new Pos ( 0 , 0 ) ) ;
// Open and close on different lines, equally indented
testEdit ( 'di{_middle_spc' , 'a{\n\tbar\n}b' , /r/ , 'di{' , 'a{}b' ) ;
testEdit ( 'di}_middle_spc' , 'a{\n\tbar\n}b' , /r/ , 'di}' , 'a{}b' ) ;
testEdit ( 'da{_middle_spc' , 'a{\n\tbar\n}b' , /r/ , 'da{' , 'ab' ) ;
testEdit ( 'da}_middle_spc' , 'a{\n\tbar\n}b' , /r/ , 'da}' , 'ab' ) ;
testEdit ( 'daB_middle_spc' , 'a{\n\tbar\n}b' , /r/ , 'daB' , 'ab' ) ;
// open and close on diff lines, open indented less than close
testEdit ( 'di{_middle_spc' , 'a{\n\tbar\n\t}b' , /r/ , 'di{' , 'a{}b' ) ;
testEdit ( 'di}_middle_spc' , 'a{\n\tbar\n\t}b' , /r/ , 'di}' , 'a{}b' ) ;
testEdit ( 'da{_middle_spc' , 'a{\n\tbar\n\t}b' , /r/ , 'da{' , 'ab' ) ;
testEdit ( 'da}_middle_spc' , 'a{\n\tbar\n\t}b' , /r/ , 'da}' , 'ab' ) ;
// open and close on diff lines, open indented more than close
testEdit ( 'di[_middle_spc' , 'a\t[\n\tbar\n]b' , /r/ , 'di[' , 'a\t[]b' ) ;
testEdit ( 'di]_middle_spc' , 'a\t[\n\tbar\n]b' , /r/ , 'di]' , 'a\t[]b' ) ;
testEdit ( 'da[_middle_spc' , 'a\t[\n\tbar\n]b' , /r/ , 'da[' , 'a\tb' ) ;
testEdit ( 'da]_middle_spc' , 'a\t[\n\tbar\n]b' , /r/ , 'da]' , 'a\tb' ) ;
// open and close on diff lines, open indented more than close
testEdit ( 'di<_middle_spc' , 'a\t<\n\tbar\n>b' , /r/ , 'di<' , 'a\t<>b' ) ;
testEdit ( 'di>_middle_spc' , 'a\t<\n\tbar\n>b' , /r/ , 'di>' , 'a\t<>b' ) ;
testEdit ( 'da<_middle_spc' , 'a\t<\n\tbar\n>b' , /r/ , 'da<' , 'a\tb' ) ;
testEdit ( 'da>_middle_spc' , 'a\t<\n\tbar\n>b' , /r/ , 'da>' , 'a\tb' ) ;
2020-10-02 13:05:50 +02:00
// deleting tag objects
testEdit ( 'dat_noop' , '<outer><inner>hello</inner></outer>' , /n/ , 'dat' , '<outer><inner>hello</inner></outer>' ) ;
testEdit ( 'dat_open_tag' , '<outer><inner>hello</inner></outer>' , /n/ , 'dat' , '<outer></outer>' , function ( cm ) {
cm . setOption ( 'mode' , 'xml' ) ;
} ) ;
testEdit ( 'dat_inside_tag' , '<outer><inner>hello</inner></outer>' , /l/ , 'dat' , '<outer></outer>' , function ( cm ) {
cm . setOption ( 'mode' , 'xml' ) ;
} ) ;
testEdit ( 'dat_close_tag' , '<outer><inner>hello</inner></outer>' , /\// , 'dat' , '<outer></outer>' , function ( cm ) {
cm . setOption ( 'mode' , 'xml' ) ;
} ) ;
testEdit ( 'dit_open_tag' , '<outer><inner>hello</inner></outer>' , /n/ , 'dit' , '<outer><inner></inner></outer>' , function ( cm ) {
cm . setOption ( 'mode' , 'xml' ) ;
} ) ;
testEdit ( 'dit_inside_tag' , '<outer><inner>hello</inner></outer>' , /l/ , 'dit' , '<outer><inner></inner></outer>' , function ( cm ) {
cm . setOption ( 'mode' , 'xml' ) ;
} ) ;
testEdit ( 'dit_close_tag' , '<outer><inner>hello</inner></outer>' , /\// , 'dit' , '<outer><inner></inner></outer>' , function ( cm ) {
cm . setOption ( 'mode' , 'xml' ) ;
} ) ;
2019-07-28 14:57:52 +02:00
function testSelection ( name , before , pos , keys , sel ) {
return testVim ( name , function ( cm , vim , helpers ) {
var ch = before . search ( pos )
var line = before . substring ( 0 , ch ) . split ( '\n' ) . length - 1 ;
if ( line ) {
ch = before . substring ( 0 , ch ) . split ( '\n' ) . pop ( ) . length ;
}
cm . setCursor ( line , ch ) ;
helpers . doKeys . apply ( this , keys . split ( '' ) ) ;
eq ( sel , cm . getSelection ( ) ) ;
} , { value : before } ) ;
}
testSelection ( 'viw_middle_spc' , 'foo \tbAr\t baz' , /A/ , 'viw' , 'bAr' ) ;
testSelection ( 'vaw_middle_spc' , 'foo \tbAr\t baz' , /A/ , 'vaw' , 'bAr\t ' ) ;
testSelection ( 'viw_middle_punct' , 'foo \tbAr,\t baz' , /A/ , 'viw' , 'bAr' ) ;
testSelection ( 'vaW_middle_punct' , 'foo \tbAr,\t baz' , /A/ , 'vaW' , 'bAr,\t ' ) ;
testSelection ( 'viw_start_spc' , 'foo \tbAr\t baz' , /b/ , 'viw' , 'bAr' ) ;
testSelection ( 'viw_end_spc' , 'foo \tbAr\t baz' , /r/ , 'viw' , 'bAr' ) ;
testSelection ( 'viw_eol' , 'foo \tbAr' , /r/ , 'viw' , 'bAr' ) ;
testSelection ( 'vi{_middle_spc' , 'a{\n\tbar\n\t}b' , /r/ , 'vi{' , '\n\tbar\n\t' ) ;
testSelection ( 'va{_middle_spc' , 'a{\n\tbar\n\t}b' , /r/ , 'va{' , '{\n\tbar\n\t}' ) ;
testVim ( 'mouse_select' , function ( cm , vim , helpers ) {
cm . setSelection ( Pos ( 0 , 2 ) , Pos ( 0 , 4 ) , { origin : '*mouse' } ) ;
is ( cm . state . vim . visualMode ) ;
is ( ! cm . state . vim . visualLine ) ;
is ( ! cm . state . vim . visualBlock ) ;
helpers . doKeys ( '<Esc>' ) ;
is ( ! cm . somethingSelected ( ) ) ;
helpers . doKeys ( 'g' , 'v' ) ;
eq ( 'cd' , cm . getSelection ( ) ) ;
} , { value : 'abcdef' } ) ;
// Operator-motion tests
testVim ( 'D' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 3 ) ;
helpers . doKeys ( 'D' ) ;
eq ( ' wo\nword2\n word3' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( 'rd1' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
helpers . assertCursorAt ( 0 , 2 ) ;
} , { value : ' word1\nword2\n word3' } ) ;
testVim ( 'C' , function ( cm , vim , helpers ) {
var curStart = makeCursor ( 0 , 3 ) ;
cm . setCursor ( curStart ) ;
helpers . doKeys ( 'C' ) ;
eq ( ' wo\nword2\n word3' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( 'rd1' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
eqCursorPos ( curStart , cm . getCursor ( ) ) ;
eq ( 'vim-insert' , cm . getOption ( 'keyMap' ) ) ;
} , { value : ' word1\nword2\n word3' } ) ;
testVim ( 'Y' , function ( cm , vim , helpers ) {
var curStart = makeCursor ( 0 , 3 ) ;
cm . setCursor ( curStart ) ;
helpers . doKeys ( 'Y' ) ;
eq ( ' word1\nword2\n word3' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( ' word1\n' , register . toString ( ) ) ;
is ( register . linewise ) ;
helpers . assertCursorAt ( 0 , 3 ) ;
} , { value : ' word1\nword2\n word3' } ) ;
testVim ( 'Yy_blockwise' , function ( cm , vim , helpers ) {
helpers . doKeys ( '<C-v>' , 'j' , '2' , 'l' , 'Y' ) ;
helpers . doKeys ( 'G' , 'p' , 'g' , 'g' ) ;
helpers . doKeys ( '<C-v>' , 'j' , '2' , 'l' , 'y' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
helpers . doKeys ( '$' , 'p' ) ;
eq ( '123456123\n123456123\n123456\n123456' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( '123\n123' , register . toString ( ) ) ;
is ( register . blockwise ) ;
helpers . assertCursorAt ( 0 , 6 ) ;
helpers . doKeys ( '$' , 'j' , 'p' ) ;
helpers . doKeys ( '$' , 'j' , 'P' ) ;
eq ( "123456123\n123456123123\n123456 121233\n123456 123" , cm . getValue ( ) ) ;
} , { value : '123456\n123456\n' } ) ;
testVim ( '~' , function ( cm , vim , helpers ) {
helpers . doKeys ( '3' , '~' ) ;
eq ( 'ABCdefg' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 3 ) ;
} , { value : 'abcdefg' } ) ;
// Action tests
testVim ( 'ctrl-a' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '-9' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 1 ) ;
helpers . doKeys ( '2' , '<C-a>' ) ;
eq ( '-7' , cm . getValue ( ) ) ;
} , { value : '-10' } ) ;
testVim ( 'ctrl-x' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '-1' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 1 ) ;
helpers . doKeys ( '2' , '<C-x>' ) ;
eq ( '-3' , cm . getValue ( ) ) ;
} , { value : '0' } ) ;
testVim ( '<C-x>/<C-a> search forward' , function ( cm , vim , helpers ) {
forEach ( [ '<C-x>' , '<C-a>' ] , function ( key ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( key ) ;
helpers . assertCursorAt ( 0 , 5 ) ;
helpers . doKeys ( 'l' ) ;
helpers . doKeys ( key ) ;
helpers . assertCursorAt ( 0 , 10 ) ;
cm . setCursor ( 0 , 11 ) ;
helpers . doKeys ( key ) ;
helpers . assertCursorAt ( 0 , 11 ) ;
} ) ;
} , { value : '__jmp1 jmp2 jmp' } ) ;
testVim ( 'insert_ctrl_w' , function ( cm , vim , helpers ) {
var curStart = makeCursor ( 0 , 10 ) ;
cm . setCursor ( curStart ) ;
helpers . doKeys ( 'a' ) ;
helpers . doKeys ( '<C-w>' ) ;
eq ( 'word1/' , cm . getValue ( ) ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
eq ( 'word2' , register . toString ( ) ) ;
is ( ! register . linewise ) ;
var curEnd = makeCursor ( 0 , 6 ) ;
eqCursorPos ( curEnd , cm . getCursor ( ) ) ;
eq ( 'vim-insert' , cm . getOption ( 'keyMap' ) ) ;
} , { value : 'word1/word2' } ) ;
testVim ( 'normal_ctrl_w' , function ( cm , vim , helpers ) {
var curStart = makeCursor ( 0 , 3 ) ;
cm . setCursor ( curStart ) ;
helpers . doKeys ( '<C-w>' ) ;
eq ( 'word' , cm . getValue ( ) ) ;
var curEnd = makeCursor ( 0 , 3 ) ;
helpers . assertCursorAt ( 0 , 3 ) ;
eqCursorPos ( curEnd , cm . getCursor ( ) ) ;
eq ( 'vim' , cm . getOption ( 'keyMap' ) ) ;
} , { value : 'word' } ) ;
testVim ( 'a' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( 'a' ) ;
helpers . assertCursorAt ( 0 , 2 ) ;
eq ( 'vim-insert' , cm . getOption ( 'keyMap' ) ) ;
} ) ;
testVim ( 'a_eol' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , lines [ 0 ] . length - 1 ) ;
helpers . doKeys ( 'a' ) ;
helpers . assertCursorAt ( 0 , lines [ 0 ] . length ) ;
eq ( 'vim-insert' , cm . getOption ( 'keyMap' ) ) ;
} ) ;
testVim ( 'A_endOfSelectedArea' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'v' , 'j' , 'l' ) ;
helpers . doKeys ( 'A' ) ;
helpers . assertCursorAt ( 1 , 2 ) ;
eq ( 'vim-insert' , cm . getOption ( 'keyMap' ) ) ;
} , { value : 'foo\nbar' } ) ;
testVim ( 'i' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( 'i' ) ;
helpers . assertCursorAt ( 0 , 1 ) ;
eq ( 'vim-insert' , cm . getOption ( 'keyMap' ) ) ;
} ) ;
testVim ( 'i_repeat' , function ( cm , vim , helpers ) {
helpers . doKeys ( '3' , 'i' ) ;
helpers . doKeys ( 'test' )
helpers . doKeys ( '<Esc>' ) ;
eq ( 'testtesttest' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 11 ) ;
} , { value : '' } ) ;
testVim ( 'i_repeat_delete' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 4 ) ;
helpers . doKeys ( '2' , 'i' ) ;
helpers . doKeys ( 'z' )
helpers . doInsertModeKeys ( 'Backspace' , 'Backspace' ) ;
helpers . doKeys ( '<Esc>' ) ;
eq ( 'abe' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 1 ) ;
} , { value : 'abcde' } ) ;
testVim ( 'insert' , function ( cm , vim , helpers ) {
helpers . doKeys ( 'i' ) ;
eq ( 'vim-insert' , cm . getOption ( 'keyMap' ) ) ;
eq ( false , cm . state . overwrite ) ;
helpers . doKeys ( '<Ins>' ) ;
eq ( 'vim-replace' , cm . getOption ( 'keyMap' ) ) ;
eq ( true , cm . state . overwrite ) ;
helpers . doKeys ( '<Ins>' ) ;
eq ( 'vim-insert' , cm . getOption ( 'keyMap' ) ) ;
eq ( false , cm . state . overwrite ) ;
} ) ;
testVim ( 'i_backspace' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 10 ) ;
helpers . doKeys ( 'i' ) ;
helpers . doInsertModeKeys ( 'Backspace' ) ;
helpers . assertCursorAt ( 0 , 9 ) ;
eq ( '012345678' , cm . getValue ( ) ) ;
} , { value : '0123456789' } ) ;
testVim ( 'i_overwrite_backspace' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 10 ) ;
helpers . doKeys ( 'i' ) ;
helpers . doKeys ( '<Ins>' ) ;
helpers . doInsertModeKeys ( 'Backspace' ) ;
helpers . assertCursorAt ( Pos ( 0 , 9 , "after" ) ) ;
eq ( '0123456789' , cm . getValue ( ) ) ;
} , { value : '0123456789' } ) ;
testVim ( 'i_forward_delete' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 3 ) ;
helpers . doKeys ( 'i' ) ;
helpers . doInsertModeKeys ( 'Delete' ) ;
helpers . assertCursorAt ( 0 , 3 ) ;
eq ( 'A124\nBCD' , cm . getValue ( ) ) ;
helpers . doInsertModeKeys ( 'Delete' ) ;
helpers . assertCursorAt ( 0 , 3 ) ;
eq ( 'A12\nBCD' , cm . getValue ( ) ) ;
helpers . doInsertModeKeys ( 'Delete' ) ;
helpers . assertCursorAt ( 0 , 3 ) ;
eq ( 'A12BCD' , cm . getValue ( ) ) ;
} , { value : 'A1234\nBCD' } ) ;
testVim ( 'forward_delete' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 3 ) ;
2020-10-02 13:05:50 +02:00
helpers . doKeys ( '<Del>' ) ;
2019-07-28 14:57:52 +02:00
helpers . assertCursorAt ( 0 , 3 ) ;
eq ( 'A124\nBCD' , cm . getValue ( ) ) ;
2020-10-02 13:05:50 +02:00
helpers . doKeys ( '<Del>' ) ;
2019-07-28 14:57:52 +02:00
helpers . assertCursorAt ( 0 , 2 ) ;
eq ( 'A12\nBCD' , cm . getValue ( ) ) ;
2020-10-02 13:05:50 +02:00
helpers . doKeys ( '<Del>' ) ;
2019-07-28 14:57:52 +02:00
helpers . assertCursorAt ( 0 , 1 ) ;
eq ( 'A1\nBCD' , cm . getValue ( ) ) ;
} , { value : 'A1234\nBCD' } ) ;
testVim ( 'A' , function ( cm , vim , helpers ) {
helpers . doKeys ( 'A' ) ;
helpers . assertCursorAt ( 0 , lines [ 0 ] . length ) ;
eq ( 'vim-insert' , cm . getOption ( 'keyMap' ) ) ;
} ) ;
testVim ( 'A_visual_block' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( '<C-v>' , '2' , 'j' , 'l' , 'l' , 'A' ) ;
helpers . doKeys ( 'hello' ) ;
eq ( 'testhello\nmehello\npleahellose' , cm . getValue ( ) ) ;
helpers . doKeys ( '<Esc>' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '.' ) ;
// TODO this doesn't work yet
// eq('teshellothello\nme hello hello\nplehelloahellose', cm.getValue());
} , { value : 'test\nme\nplease' } ) ;
testVim ( 'I' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 4 ) ;
helpers . doKeys ( 'I' ) ;
helpers . assertCursorAt ( 0 , lines [ 0 ] . textStart ) ;
eq ( 'vim-insert' , cm . getOption ( 'keyMap' ) ) ;
} ) ;
testVim ( 'I_repeat' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( '3' , 'I' ) ;
helpers . doKeys ( 'test' )
helpers . doKeys ( '<Esc>' ) ;
eq ( 'testtesttestblah' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 11 ) ;
} , { value : 'blah' } ) ;
testVim ( 'I_visual_block' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '<C-v>' , '2' , 'j' , 'l' , 'l' , 'I' ) ;
helpers . doKeys ( 'hello' ) ;
eq ( 'hellotest\nhellome\nhelloplease' , cm . getValue ( ) ) ;
} , { value : 'test\nme\nplease' } ) ;
testVim ( 'o' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 4 ) ;
helpers . doKeys ( 'o' ) ;
eq ( 'word1\n\nword2' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 1 , 0 ) ;
eq ( 'vim-insert' , cm . getOption ( 'keyMap' ) ) ;
} , { value : 'word1\nword2' } ) ;
testVim ( 'o_repeat' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '3' , 'o' ) ;
helpers . doKeys ( 'test' )
helpers . doKeys ( '<Esc>' ) ;
eq ( '\ntest\ntest\ntest' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 3 , 3 ) ;
} , { value : '' } ) ;
testVim ( 'O' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 4 ) ;
helpers . doKeys ( 'O' ) ;
eq ( '\nword1\nword2' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
eq ( 'vim-insert' , cm . getOption ( 'keyMap' ) ) ;
} , { value : 'word1\nword2' } ) ;
testVim ( 'J' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 4 ) ;
helpers . doKeys ( 'J' ) ;
var expectedValue = 'word1 word2\nword3\n word4' ;
eq ( expectedValue , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , expectedValue . indexOf ( 'word2' ) - 1 ) ;
} , { value : 'word1 \n word2\nword3\n word4' } ) ;
testVim ( 'J_repeat' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 4 ) ;
helpers . doKeys ( '3' , 'J' ) ;
var expectedValue = 'word1 word2 word3\n word4' ;
eq ( expectedValue , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , expectedValue . indexOf ( 'word3' ) - 1 ) ;
} , { value : 'word1 \n word2\nword3\n word4' } ) ;
2020-10-02 13:05:50 +02:00
testVim ( 'gJ' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 4 ) ;
helpers . doKeys ( 'g' , 'J' ) ;
eq ( 'word1word2 \n word3' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 5 ) ;
helpers . doKeys ( 'g' , 'J' ) ;
eq ( 'word1word2 word3' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 11 ) ;
} , { value : 'word1\nword2 \n word3' } ) ;
testVim ( 'gi' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 5 ) ;
helpers . doKeys ( 'g' , 'I' ) ;
helpers . doKeys ( 'a' , 'a' , '<Esc>' , 'k' ) ;
eq ( '12\naa xxxx' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 1 ) ;
helpers . doKeys ( 'g' , 'i' ) ;
helpers . assertCursorAt ( 1 , 2 ) ;
eq ( 'vim-insert' , cm . getOption ( 'keyMap' ) ) ;
} , { value : '12\n xxxx' } ) ;
2019-07-28 14:57:52 +02:00
testVim ( 'p' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . getRegisterController ( ) . pushText ( '"' , 'yank' , 'abc\ndef' , false ) ;
helpers . doKeys ( 'p' ) ;
eq ( '__abc\ndef_' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 1 , 2 ) ;
} , { value : '___' } ) ;
testVim ( 'p_register' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . getRegisterController ( ) . getRegister ( 'a' ) . setText ( 'abc\ndef' , false ) ;
helpers . doKeys ( '"' , 'a' , 'p' ) ;
eq ( '__abc\ndef_' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 1 , 2 ) ;
} , { value : '___' } ) ;
testVim ( 'p_wrong_register' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . getRegisterController ( ) . getRegister ( 'a' ) . setText ( 'abc\ndef' , false ) ;
helpers . doKeys ( 'p' ) ;
eq ( '___' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 1 ) ;
} , { value : '___' } ) ;
testVim ( 'p_line' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . getRegisterController ( ) . pushText ( '"' , 'yank' , ' a\nd\n' , true ) ;
helpers . doKeys ( '2' , 'p' ) ;
eq ( '___\n a\nd\n a\nd' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 1 , 2 ) ;
} , { value : '___' } ) ;
testVim ( 'p_lastline' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . getRegisterController ( ) . pushText ( '"' , 'yank' , ' a\nd' , true ) ;
helpers . doKeys ( '2' , 'p' ) ;
eq ( '___\n a\nd\n a\nd' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 1 , 2 ) ;
} , { value : '___' } ) ;
testVim ( ']p_first_indent_is_smaller' , function ( cm , vim , helpers ) {
helpers . getRegisterController ( ) . pushText ( '"' , 'yank' , ' abc\n def\n' , true ) ;
helpers . doKeys ( ']' , 'p' ) ;
eq ( ' ___\n abc\n def' , cm . getValue ( ) ) ;
} , { value : ' ___' } ) ;
testVim ( ']p_first_indent_is_larger' , function ( cm , vim , helpers ) {
helpers . getRegisterController ( ) . pushText ( '"' , 'yank' , ' abc\n def\n' , true ) ;
helpers . doKeys ( ']' , 'p' ) ;
eq ( ' ___\n abc\ndef' , cm . getValue ( ) ) ;
} , { value : ' ___' } ) ;
testVim ( ']p_with_tab_indents' , function ( cm , vim , helpers ) {
helpers . getRegisterController ( ) . pushText ( '"' , 'yank' , '\t\tabc\n\t\t\tdef\n' , true ) ;
helpers . doKeys ( ']' , 'p' ) ;
eq ( '\t___\n\tabc\n\t\tdef' , cm . getValue ( ) ) ;
} , { value : '\t___' , indentWithTabs : true } ) ;
testVim ( ']p_with_spaces_translated_to_tabs' , function ( cm , vim , helpers ) {
helpers . getRegisterController ( ) . pushText ( '"' , 'yank' , ' abc\n def\n' , true ) ;
helpers . doKeys ( ']' , 'p' ) ;
eq ( '\t___\n\tabc\n\t\tdef' , cm . getValue ( ) ) ;
} , { value : '\t___' , indentWithTabs : true , tabSize : 2 } ) ;
testVim ( '[p' , function ( cm , vim , helpers ) {
helpers . getRegisterController ( ) . pushText ( '"' , 'yank' , ' abc\n def\n' , true ) ;
helpers . doKeys ( '[' , 'p' ) ;
eq ( ' abc\n def\n ___' , cm . getValue ( ) ) ;
} , { value : ' ___' } ) ;
testVim ( 'P' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . getRegisterController ( ) . pushText ( '"' , 'yank' , 'abc\ndef' , false ) ;
helpers . doKeys ( 'P' ) ;
eq ( '_abc\ndef__' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 1 , 3 ) ;
} , { value : '___' } ) ;
testVim ( 'P_line' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . getRegisterController ( ) . pushText ( '"' , 'yank' , ' a\nd\n' , true ) ;
helpers . doKeys ( '2' , 'P' ) ;
eq ( ' a\nd\n a\nd\n___' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 2 ) ;
} , { value : '___' } ) ;
testVim ( 'r' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( '3' , 'r' , 'u' ) ;
eq ( 'wuuuet\nanother' , cm . getValue ( ) , '3r failed' ) ;
helpers . assertCursorAt ( 0 , 3 ) ;
cm . setCursor ( 0 , 4 ) ;
helpers . doKeys ( 'v' , 'j' , 'h' , 'r' , '<Space>' ) ;
eq ( 'wuuu \n her' , cm . getValue ( ) , 'Replacing selection by space-characters failed' ) ;
cm . setValue ( "ox" ) ;
helpers . doKeys ( 'r' , '<C-c>' ) ;
eq ( 'ox' , cm . getValue ( ) ) ;
helpers . doKeys ( 'r' , '<Del>' ) ;
eq ( 'ox' , cm . getValue ( ) ) ;
helpers . doKeys ( 'r' , '<CR>' ) ;
eq ( '\nx' , cm . getValue ( ) ) ;
} , { value : 'wordet\nanother' } ) ;
testVim ( 'r_visual_block' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 3 ) ;
helpers . doKeys ( '<C-v>' , 'k' , 'k' , 'h' , 'h' , 'r' , 'l' ) ;
eq ( '1lll\n5lll\nalllefg' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-v>' , 'l' , 'j' , 'r' , '<Space>' ) ;
eq ( '1 l\n5 l\nalllefg' , cm . getValue ( ) ) ;
cm . setCursor ( 2 , 0 ) ;
helpers . doKeys ( 'o' ) ;
helpers . doKeys ( '\t\t' )
helpers . doKeys ( '<Esc>' ) ;
helpers . doKeys ( '<C-v>' , 'h' , 'h' , 'r' , 'r' ) ;
eq ( '1 l\n5 l\nalllefg\nrrrrrrrr' , cm . getValue ( ) ) ;
} , { value : '1234\n5678\nabcdefg' } ) ;
testVim ( 'R' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( 'R' ) ;
helpers . assertCursorAt ( 0 , 1 ) ;
eq ( 'vim-replace' , cm . getOption ( 'keyMap' ) ) ;
is ( cm . state . overwrite , 'Setting overwrite state failed' ) ;
} ) ;
2020-10-02 13:05:50 +02:00
testVim ( 'R_visual' , function ( cm , vim , helpers ) {
helpers . doKeys ( '<C-v>' , 'j' , 'R' , '0' , '<Esc>' ) ;
eq ( '0\nb33\nc44\nc55' , cm . getValue ( ) ) ;
helpers . doKeys ( '2' , 'j' , '.' ) ;
eq ( '0\nb33\n0' , cm . getValue ( ) ) ;
helpers . doKeys ( 'k' , 'v' , 'R' , '1' , '<Esc>' ) ;
eq ( '0\n1\n0' , cm . getValue ( ) ) ;
helpers . doKeys ( 'k' , '.' ) ;
eq ( '1\n1\n0' , cm . getValue ( ) ) ;
helpers . doKeys ( 'p' ) ;
eq ( '1\n0\n1\n0' , cm . getValue ( ) ) ;
} , { value : 'a11\na22\nb33\nc44\nc55' } ) ;
2019-07-28 14:57:52 +02:00
testVim ( 'mark' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 2 ) ;
helpers . doKeys ( 'm' , 't' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '`' , 't' ) ;
helpers . assertCursorAt ( 2 , 2 ) ;
cm . setCursor ( 2 , 0 ) ;
cm . replaceRange ( ' h' , cm . getCursor ( ) ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '\'' , 't' ) ;
helpers . assertCursorAt ( 2 , 3 ) ;
} ) ;
testVim ( 'mark\'' , function ( cm , vim , helpers ) {
2020-10-02 13:05:50 +02:00
// motions that do not update jumplist
2019-07-28 14:57:52 +02:00
cm . setCursor ( 2 , 2 ) ;
helpers . doKeys ( '`' , '\'' ) ;
2020-10-02 13:05:50 +02:00
helpers . assertCursorAt ( 0 , 0 ) ;
helpers . doKeys ( 'j' , '3' , 'l' ) ;
helpers . doKeys ( '`' , '`' ) ;
2019-07-28 14:57:52 +02:00
helpers . assertCursorAt ( 2 , 2 ) ;
2020-10-02 13:05:50 +02:00
helpers . doKeys ( '`' , '`' ) ;
helpers . assertCursorAt ( 1 , 3 ) ;
// motions that update jumplist
cm . openDialog = helpers . fakeOpenDialog ( '=' ) ;
helpers . doKeys ( '/' ) ;
helpers . assertCursorAt ( 6 , 20 ) ;
helpers . doKeys ( '`' , '`' ) ;
helpers . assertCursorAt ( 1 , 3 ) ;
2019-07-28 14:57:52 +02:00
helpers . doKeys ( '\'' , '\'' ) ;
2020-10-02 13:05:50 +02:00
helpers . assertCursorAt ( 6 , 2 ) ;
helpers . doKeys ( '\'' , '`' ) ;
helpers . assertCursorAt ( 1 , 1 ) ;
// edits
helpers . doKeys ( 'g' , 'I' , '\n' , '<Esc>' , 'l' ) ;
helpers . doKeys ( '`' , '`' ) ;
helpers . assertCursorAt ( 7 , 2 ) ;
helpers . doKeys ( '`' , '`' ) ;
helpers . assertCursorAt ( 2 , 1 ) ;
2019-07-28 14:57:52 +02:00
} ) ;
testVim ( 'mark.' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'O' , 'testing' , '<Esc>' ) ;
cm . setCursor ( 3 , 3 ) ;
helpers . doKeys ( '\'' , '.' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
cm . setCursor ( 4 , 4 ) ;
helpers . doKeys ( '`' , '.' ) ;
helpers . assertCursorAt ( 0 , 6 ) ;
} ) ;
testVim ( 'jumpToMark_next' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 2 ) ;
helpers . doKeys ( 'm' , 't' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( ']' , '`' ) ;
helpers . assertCursorAt ( 2 , 2 ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( ']' , '\'' ) ;
helpers . assertCursorAt ( 2 , 0 ) ;
} ) ;
testVim ( 'jumpToMark_next_repeat' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 2 ) ;
helpers . doKeys ( 'm' , 'a' ) ;
cm . setCursor ( 3 , 2 ) ;
helpers . doKeys ( 'm' , 'b' ) ;
cm . setCursor ( 4 , 2 ) ;
helpers . doKeys ( 'm' , 'c' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '2' , ']' , '`' ) ;
helpers . assertCursorAt ( 3 , 2 ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '2' , ']' , '\'' ) ;
helpers . assertCursorAt ( 3 , 1 ) ;
} ) ;
testVim ( 'jumpToMark_next_sameline' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 0 ) ;
helpers . doKeys ( 'm' , 'a' ) ;
cm . setCursor ( 2 , 4 ) ;
helpers . doKeys ( 'm' , 'b' ) ;
cm . setCursor ( 2 , 2 ) ;
helpers . doKeys ( ']' , '`' ) ;
helpers . assertCursorAt ( 2 , 4 ) ;
} ) ;
testVim ( 'jumpToMark_next_onlyprev' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 0 ) ;
helpers . doKeys ( 'm' , 'a' ) ;
cm . setCursor ( 4 , 0 ) ;
helpers . doKeys ( ']' , '`' ) ;
helpers . assertCursorAt ( 4 , 0 ) ;
} ) ;
testVim ( 'jumpToMark_next_nomark' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 2 ) ;
helpers . doKeys ( ']' , '`' ) ;
helpers . assertCursorAt ( 2 , 2 ) ;
helpers . doKeys ( ']' , '\'' ) ;
helpers . assertCursorAt ( 2 , 0 ) ;
} ) ;
testVim ( 'jumpToMark_next_linewise_over' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 2 ) ;
helpers . doKeys ( 'm' , 'a' ) ;
cm . setCursor ( 3 , 4 ) ;
helpers . doKeys ( 'm' , 'b' ) ;
cm . setCursor ( 2 , 1 ) ;
helpers . doKeys ( ']' , '\'' ) ;
helpers . assertCursorAt ( 3 , 1 ) ;
} ) ;
testVim ( 'jumpToMark_next_action' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 2 ) ;
helpers . doKeys ( 'm' , 't' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'd' , ']' , '`' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
var actual = cm . getLine ( 0 ) ;
var expected = 'pop pop 0 1 2 3 4' ;
eq ( actual , expected , "Deleting while jumping to the next mark failed." ) ;
} ) ;
testVim ( 'jumpToMark_next_line_action' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 2 ) ;
helpers . doKeys ( 'm' , 't' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'd' , ']' , '\'' ) ;
helpers . assertCursorAt ( 0 , 1 ) ;
var actual = cm . getLine ( 0 ) ;
var expected = ' (a) [b] {c} '
eq ( actual , expected , "Deleting while jumping to the next mark line failed." ) ;
} ) ;
testVim ( 'jumpToMark_prev' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 2 ) ;
helpers . doKeys ( 'm' , 't' ) ;
cm . setCursor ( 4 , 0 ) ;
helpers . doKeys ( '[' , '`' ) ;
helpers . assertCursorAt ( 2 , 2 ) ;
cm . setCursor ( 4 , 0 ) ;
helpers . doKeys ( '[' , '\'' ) ;
helpers . assertCursorAt ( 2 , 0 ) ;
} ) ;
testVim ( 'jumpToMark_prev_repeat' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 2 ) ;
helpers . doKeys ( 'm' , 'a' ) ;
cm . setCursor ( 3 , 2 ) ;
helpers . doKeys ( 'm' , 'b' ) ;
cm . setCursor ( 4 , 2 ) ;
helpers . doKeys ( 'm' , 'c' ) ;
cm . setCursor ( 5 , 0 ) ;
helpers . doKeys ( '2' , '[' , '`' ) ;
helpers . assertCursorAt ( 3 , 2 ) ;
cm . setCursor ( 5 , 0 ) ;
helpers . doKeys ( '2' , '[' , '\'' ) ;
helpers . assertCursorAt ( 3 , 1 ) ;
} ) ;
testVim ( 'jumpToMark_prev_sameline' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 0 ) ;
helpers . doKeys ( 'm' , 'a' ) ;
cm . setCursor ( 2 , 4 ) ;
helpers . doKeys ( 'm' , 'b' ) ;
cm . setCursor ( 2 , 2 ) ;
helpers . doKeys ( '[' , '`' ) ;
helpers . assertCursorAt ( 2 , 0 ) ;
} ) ;
testVim ( 'jumpToMark_prev_onlynext' , function ( cm , vim , helpers ) {
cm . setCursor ( 4 , 4 ) ;
helpers . doKeys ( 'm' , 'a' ) ;
cm . setCursor ( 2 , 0 ) ;
helpers . doKeys ( '[' , '`' ) ;
helpers . assertCursorAt ( 2 , 0 ) ;
} ) ;
testVim ( 'jumpToMark_prev_nomark' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 2 ) ;
helpers . doKeys ( '[' , '`' ) ;
helpers . assertCursorAt ( 2 , 2 ) ;
helpers . doKeys ( '[' , '\'' ) ;
helpers . assertCursorAt ( 2 , 0 ) ;
} ) ;
testVim ( 'jumpToMark_prev_linewise_over' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 2 ) ;
helpers . doKeys ( 'm' , 'a' ) ;
cm . setCursor ( 3 , 4 ) ;
helpers . doKeys ( 'm' , 'b' ) ;
cm . setCursor ( 3 , 6 ) ;
helpers . doKeys ( '[' , '\'' ) ;
helpers . assertCursorAt ( 2 , 0 ) ;
} ) ;
testVim ( 'delmark_single' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 2 ) ;
helpers . doKeys ( 'm' , 't' ) ;
helpers . doEx ( 'delmarks t' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '`' , 't' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
} ) ;
testVim ( 'delmark_range' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 2 ) ;
helpers . doKeys ( 'm' , 'a' ) ;
cm . setCursor ( 2 , 2 ) ;
helpers . doKeys ( 'm' , 'b' ) ;
cm . setCursor ( 3 , 2 ) ;
helpers . doKeys ( 'm' , 'c' ) ;
cm . setCursor ( 4 , 2 ) ;
helpers . doKeys ( 'm' , 'd' ) ;
cm . setCursor ( 5 , 2 ) ;
helpers . doKeys ( 'm' , 'e' ) ;
helpers . doEx ( 'delmarks b-d' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '`' , 'a' ) ;
helpers . assertCursorAt ( 1 , 2 ) ;
helpers . doKeys ( '`' , 'b' ) ;
helpers . assertCursorAt ( 1 , 2 ) ;
helpers . doKeys ( '`' , 'c' ) ;
helpers . assertCursorAt ( 1 , 2 ) ;
helpers . doKeys ( '`' , 'd' ) ;
helpers . assertCursorAt ( 1 , 2 ) ;
helpers . doKeys ( '`' , 'e' ) ;
helpers . assertCursorAt ( 5 , 2 ) ;
} ) ;
testVim ( 'delmark_multi' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 2 ) ;
helpers . doKeys ( 'm' , 'a' ) ;
cm . setCursor ( 2 , 2 ) ;
helpers . doKeys ( 'm' , 'b' ) ;
cm . setCursor ( 3 , 2 ) ;
helpers . doKeys ( 'm' , 'c' ) ;
cm . setCursor ( 4 , 2 ) ;
helpers . doKeys ( 'm' , 'd' ) ;
cm . setCursor ( 5 , 2 ) ;
helpers . doKeys ( 'm' , 'e' ) ;
helpers . doEx ( 'delmarks bcd' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '`' , 'a' ) ;
helpers . assertCursorAt ( 1 , 2 ) ;
helpers . doKeys ( '`' , 'b' ) ;
helpers . assertCursorAt ( 1 , 2 ) ;
helpers . doKeys ( '`' , 'c' ) ;
helpers . assertCursorAt ( 1 , 2 ) ;
helpers . doKeys ( '`' , 'd' ) ;
helpers . assertCursorAt ( 1 , 2 ) ;
helpers . doKeys ( '`' , 'e' ) ;
helpers . assertCursorAt ( 5 , 2 ) ;
} ) ;
testVim ( 'delmark_multi_space' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 2 ) ;
helpers . doKeys ( 'm' , 'a' ) ;
cm . setCursor ( 2 , 2 ) ;
helpers . doKeys ( 'm' , 'b' ) ;
cm . setCursor ( 3 , 2 ) ;
helpers . doKeys ( 'm' , 'c' ) ;
cm . setCursor ( 4 , 2 ) ;
helpers . doKeys ( 'm' , 'd' ) ;
cm . setCursor ( 5 , 2 ) ;
helpers . doKeys ( 'm' , 'e' ) ;
helpers . doEx ( 'delmarks b c d' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '`' , 'a' ) ;
helpers . assertCursorAt ( 1 , 2 ) ;
helpers . doKeys ( '`' , 'b' ) ;
helpers . assertCursorAt ( 1 , 2 ) ;
helpers . doKeys ( '`' , 'c' ) ;
helpers . assertCursorAt ( 1 , 2 ) ;
helpers . doKeys ( '`' , 'd' ) ;
helpers . assertCursorAt ( 1 , 2 ) ;
helpers . doKeys ( '`' , 'e' ) ;
helpers . assertCursorAt ( 5 , 2 ) ;
} ) ;
testVim ( 'delmark_all' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 2 ) ;
helpers . doKeys ( 'm' , 'a' ) ;
cm . setCursor ( 2 , 2 ) ;
helpers . doKeys ( 'm' , 'b' ) ;
cm . setCursor ( 3 , 2 ) ;
helpers . doKeys ( 'm' , 'c' ) ;
cm . setCursor ( 4 , 2 ) ;
helpers . doKeys ( 'm' , 'd' ) ;
cm . setCursor ( 5 , 2 ) ;
helpers . doKeys ( 'm' , 'e' ) ;
helpers . doEx ( 'delmarks a b-de' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '`' , 'a' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
helpers . doKeys ( '`' , 'b' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
helpers . doKeys ( '`' , 'c' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
helpers . doKeys ( '`' , 'd' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
helpers . doKeys ( '`' , 'e' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
} ) ;
testVim ( 'visual' , function ( cm , vim , helpers ) {
helpers . doKeys ( 'l' , 'v' , 'l' , 'l' ) ;
helpers . assertCursorAt ( 0 , 4 ) ;
eqCursorPos ( makeCursor ( 0 , 1 ) , cm . getCursor ( 'anchor' ) ) ;
helpers . doKeys ( 'd' ) ;
eq ( '15' , cm . getValue ( ) ) ;
} , { value : '12345' } ) ;
testVim ( 'visual_yank' , function ( cm , vim , helpers ) {
helpers . doKeys ( 'v' , '3' , 'l' , 'y' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
helpers . doKeys ( 'p' ) ;
eq ( 'aa te test for yank' , cm . getValue ( ) ) ;
} , { value : 'a test for yank' } )
testVim ( 'visual_w' , function ( cm , vim , helpers ) {
helpers . doKeys ( 'v' , 'w' ) ;
eq ( cm . getSelection ( ) , 'motion t' ) ;
} , { value : 'motion test' } ) ;
testVim ( 'visual_initial_selection' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( 'v' ) ;
cm . getSelection ( 'n' ) ;
} , { value : 'init' } ) ;
testVim ( 'visual_crossover_left' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 2 ) ;
helpers . doKeys ( 'v' , 'l' , 'h' , 'h' ) ;
cm . getSelection ( 'ro' ) ;
} , { value : 'cross' } ) ;
testVim ( 'visual_crossover_left' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 2 ) ;
helpers . doKeys ( 'v' , 'h' , 'l' , 'l' ) ;
cm . getSelection ( 'os' ) ;
} , { value : 'cross' } ) ;
testVim ( 'visual_crossover_up' , function ( cm , vim , helpers ) {
cm . setCursor ( 3 , 2 ) ;
helpers . doKeys ( 'v' , 'j' , 'k' , 'k' ) ;
eqCursorPos ( Pos ( 2 , 2 ) , cm . getCursor ( 'head' ) ) ;
eqCursorPos ( Pos ( 3 , 3 ) , cm . getCursor ( 'anchor' ) ) ;
helpers . doKeys ( 'k' ) ;
eqCursorPos ( Pos ( 1 , 2 ) , cm . getCursor ( 'head' ) ) ;
eqCursorPos ( Pos ( 3 , 3 ) , cm . getCursor ( 'anchor' ) ) ;
} , { value : 'cross\ncross\ncross\ncross\ncross\n' } ) ;
testVim ( 'visual_crossover_down' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 2 ) ;
helpers . doKeys ( 'v' , 'k' , 'j' , 'j' ) ;
eqCursorPos ( Pos ( 2 , 3 ) , cm . getCursor ( 'head' ) ) ;
eqCursorPos ( Pos ( 1 , 2 ) , cm . getCursor ( 'anchor' ) ) ;
helpers . doKeys ( 'j' ) ;
eqCursorPos ( Pos ( 3 , 3 ) , cm . getCursor ( 'head' ) ) ;
eqCursorPos ( Pos ( 1 , 2 ) , cm . getCursor ( 'anchor' ) ) ;
} , { value : 'cross\ncross\ncross\ncross\ncross\n' } ) ;
testVim ( 'visual_exit' , function ( cm , vim , helpers ) {
helpers . doKeys ( '<C-v>' , 'l' , 'j' , 'j' , '<Esc>' ) ;
eqCursorPos ( cm . getCursor ( 'anchor' ) , cm . getCursor ( 'head' ) ) ;
eq ( vim . visualMode , false ) ;
} , { value : 'hello\nworld\nfoo' } ) ;
testVim ( 'visual_line' , function ( cm , vim , helpers ) {
helpers . doKeys ( 'l' , 'V' , 'l' , 'j' , 'j' , 'd' ) ;
eq ( ' 4\n 5' , cm . getValue ( ) ) ;
} , { value : ' 1\n 2\n 3\n 4\n 5' } ) ;
testVim ( 'visual_block_move_to_eol' , function ( cm , vim , helpers ) {
// moveToEol should move all block cursors to end of line
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '<C-v>' , 'G' , '$' ) ;
var selections = cm . getSelections ( ) . join ( ) ;
eq ( '123,45,6' , selections ) ;
// Checks that with cursor at Infinity, finding words backwards still works.
helpers . doKeys ( '2' , 'k' , 'b' ) ;
selections = cm . getSelections ( ) . join ( ) ;
eq ( '1' , selections ) ;
} , { value : '123\n45\n6' } ) ;
testVim ( 'visual_block_different_line_lengths' , function ( cm , vim , helpers ) {
// test the block selection with lines of different length
// i.e. extending the selection
// till the end of the longest line.
helpers . doKeys ( '<C-v>' , 'l' , 'j' , 'j' , '6' , 'l' , 'd' ) ;
helpers . doKeys ( 'd' , 'd' , 'd' , 'd' ) ;
eq ( '' , cm . getValue ( ) ) ;
} , { value : '1234\n5678\nabcdefg' } ) ;
testVim ( 'visual_block_truncate_on_short_line' , function ( cm , vim , helpers ) {
// check for left side selection in case
// of moving up to a shorter line.
cm . replaceRange ( '' , cm . getCursor ( ) ) ;
cm . setCursor ( 3 , 4 ) ;
helpers . doKeys ( '<C-v>' , 'l' , 'k' , 'k' , 'd' ) ;
eq ( 'hello world\n{\ntis\nsa!' , cm . getValue ( ) ) ;
} , { value : 'hello world\n{\nthis is\nsparta!' } ) ;
testVim ( 'visual_block_corners' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 2 ) ;
helpers . doKeys ( '<C-v>' , '2' , 'l' , 'k' ) ;
// circle around the anchor
// and check the selections
var selections = cm . getSelections ( ) ;
eq ( '345891' , selections . join ( '' ) ) ;
helpers . doKeys ( '4' , 'h' ) ;
selections = cm . getSelections ( ) ;
eq ( '123678' , selections . join ( '' ) ) ;
helpers . doKeys ( 'j' , 'j' ) ;
selections = cm . getSelections ( ) ;
eq ( '678abc' , selections . join ( '' ) ) ;
helpers . doKeys ( '4' , 'l' ) ;
selections = cm . getSelections ( ) ;
eq ( '891cde' , selections . join ( '' ) ) ;
} , { value : '12345\n67891\nabcde' } ) ;
testVim ( 'visual_block_mode_switch' , function ( cm , vim , helpers ) {
// switch between visual modes
cm . setCursor ( 1 , 1 ) ;
// blockwise to characterwise visual
helpers . doKeys ( '<C-v>' , 'j' , 'l' , 'v' ) ;
var selections = cm . getSelections ( ) ;
eq ( '7891\nabc' , selections . join ( '' ) ) ;
// characterwise to blockwise
helpers . doKeys ( '<C-v>' ) ;
selections = cm . getSelections ( ) ;
eq ( '78bc' , selections . join ( '' ) ) ;
// blockwise to linewise visual
helpers . doKeys ( 'V' ) ;
selections = cm . getSelections ( ) ;
eq ( '67891\nabcde' , selections . join ( '' ) ) ;
} , { value : '12345\n67891\nabcde' } ) ;
testVim ( 'visual_block_crossing_short_line' , function ( cm , vim , helpers ) {
// visual block with long and short lines
cm . setCursor ( 0 , 3 ) ;
helpers . doKeys ( '<C-v>' , 'j' , 'j' , 'j' ) ;
var selections = cm . getSelections ( ) . join ( ) ;
eq ( '4,,d,b' , selections ) ;
helpers . doKeys ( '3' , 'k' ) ;
selections = cm . getSelections ( ) . join ( ) ;
eq ( '4' , selections ) ;
helpers . doKeys ( '5' , 'j' , 'k' ) ;
selections = cm . getSelections ( ) . join ( "" ) ;
eq ( 10 , selections . length ) ;
} , { value : '123456\n78\nabcdefg\nfoobar\n}\n' } ) ;
testVim ( 'visual_block_curPos_on_exit' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '<C-v>' , '3' , 'l' , '<Esc>' ) ;
eqCursorPos ( makeCursor ( 0 , 3 ) , cm . getCursor ( ) ) ;
helpers . doKeys ( 'h' , '<C-v>' , '2' , 'j' , '3' , 'l' ) ;
eq ( cm . getSelections ( ) . join ( ) , "3456,,cdef" ) ;
helpers . doKeys ( '4' , 'h' ) ;
eq ( cm . getSelections ( ) . join ( ) , "23,8,bc" ) ;
helpers . doKeys ( '2' , 'l' ) ;
eq ( cm . getSelections ( ) . join ( ) , "34,,cd" ) ;
} , { value : '123456\n78\nabcdefg\nfoobar' } ) ;
testVim ( 'visual_marks' , function ( cm , vim , helpers ) {
helpers . doKeys ( 'l' , 'v' , 'l' , 'l' , 'j' , 'j' , 'v' ) ;
// Test visual mode marks
cm . setCursor ( 2 , 1 ) ;
helpers . doKeys ( '\'' , '<' ) ;
helpers . assertCursorAt ( 0 , 1 ) ;
helpers . doKeys ( '\'' , '>' ) ;
helpers . assertCursorAt ( 2 , 0 ) ;
} ) ;
testVim ( 'visual_join' , function ( cm , vim , helpers ) {
helpers . doKeys ( 'l' , 'V' , 'l' , 'j' , 'j' , 'J' ) ;
eq ( ' 1 2 3\n 4\n 5' , cm . getValue ( ) ) ;
is ( ! vim . visualMode ) ;
} , { value : ' 1\n 2\n 3\n 4\n 5' } ) ;
testVim ( 'visual_join_2' , function ( cm , vim , helpers ) {
helpers . doKeys ( 'G' , 'V' , 'g' , 'g' , 'J' ) ;
eq ( '1 2 3 4 5 6 ' , cm . getValue ( ) ) ;
is ( ! vim . visualMode ) ;
} , { value : '1\n2\n3\n4\n5\n6\n' } ) ;
testVim ( 'visual_blank' , function ( cm , vim , helpers ) {
helpers . doKeys ( 'v' , 'k' ) ;
eq ( vim . visualMode , true ) ;
} , { value : '\n' } ) ;
testVim ( 'reselect_visual' , function ( cm , vim , helpers ) {
helpers . doKeys ( 'l' , 'v' , 'l' , 'l' , 'l' , 'y' , 'g' , 'v' ) ;
helpers . assertCursorAt ( 0 , 5 ) ;
eqCursorPos ( makeCursor ( 0 , 1 ) , cm . getCursor ( 'anchor' ) ) ;
helpers . doKeys ( 'v' ) ;
cm . setCursor ( 1 , 0 ) ;
helpers . doKeys ( 'v' , 'l' , 'l' , 'p' ) ;
eq ( '123456\n2345\nbar' , cm . getValue ( ) ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'g' , 'v' ) ;
// here the fake cursor is at (1, 3)
helpers . assertCursorAt ( 1 , 4 ) ;
eqCursorPos ( makeCursor ( 1 , 0 ) , cm . getCursor ( 'anchor' ) ) ;
helpers . doKeys ( 'v' ) ;
cm . setCursor ( 2 , 0 ) ;
helpers . doKeys ( 'v' , 'l' , 'l' , 'g' , 'v' ) ;
helpers . assertCursorAt ( 1 , 4 ) ;
eqCursorPos ( makeCursor ( 1 , 0 ) , cm . getCursor ( 'anchor' ) ) ;
helpers . doKeys ( 'g' , 'v' ) ;
helpers . assertCursorAt ( 2 , 3 ) ;
eqCursorPos ( makeCursor ( 2 , 0 ) , cm . getCursor ( 'anchor' ) ) ;
eq ( '123456\n2345\nbar' , cm . getValue ( ) ) ;
} , { value : '123456\nfoo\nbar' } ) ;
testVim ( 'reselect_visual_line' , function ( cm , vim , helpers ) {
helpers . doKeys ( 'l' , 'V' , 'j' , 'j' , 'V' , 'g' , 'v' , 'd' ) ;
eq ( 'foo\nand\nbar' , cm . getValue ( ) ) ;
cm . setCursor ( 1 , 0 ) ;
helpers . doKeys ( 'V' , 'y' , 'j' ) ;
helpers . doKeys ( 'V' , 'p' , 'g' , 'v' , 'd' ) ;
eq ( 'foo\nand' , cm . getValue ( ) ) ;
} , { value : 'hello\nthis\nis\nfoo\nand\nbar' } ) ;
testVim ( 'reselect_visual_block' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 2 ) ;
helpers . doKeys ( '<C-v>' , 'k' , 'h' , '<C-v>' ) ;
cm . setCursor ( 2 , 1 ) ;
helpers . doKeys ( 'v' , 'l' , 'g' , 'v' ) ;
eqCursorPos ( Pos ( 1 , 2 ) , vim . sel . anchor ) ;
eqCursorPos ( Pos ( 0 , 1 ) , vim . sel . head ) ;
// Ensure selection is done with visual block mode rather than one
// continuous range.
eq ( cm . getSelections ( ) . join ( '' ) , '23oo' )
helpers . doKeys ( 'g' , 'v' ) ;
eqCursorPos ( Pos ( 2 , 1 ) , vim . sel . anchor ) ;
eqCursorPos ( Pos ( 2 , 2 ) , vim . sel . head ) ;
helpers . doKeys ( '<Esc>' ) ;
// Ensure selection of deleted range
cm . setCursor ( 1 , 1 ) ;
helpers . doKeys ( 'v' , '<C-v>' , 'j' , 'd' , 'g' , 'v' ) ;
eq ( cm . getSelections ( ) . join ( '' ) , 'or' ) ;
} , { value : '123456\nfoo\nbar' } ) ;
testVim ( 's_normal' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( 's' ) ;
helpers . doKeys ( '<Esc>' ) ;
eq ( 'ac' , cm . getValue ( ) ) ;
} , { value : 'abc' } ) ;
testVim ( 's_visual' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( 'v' , 's' ) ;
helpers . doKeys ( '<Esc>' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
eq ( 'ac' , cm . getValue ( ) ) ;
} , { value : 'abc' } ) ;
testVim ( 'o_visual' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'v' , 'l' , 'l' , 'l' , 'o' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
helpers . doKeys ( 'v' , 'v' , 'j' , 'j' , 'j' , 'o' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
helpers . doKeys ( 'O' ) ;
helpers . doKeys ( 'l' , 'l' )
helpers . assertCursorAt ( 3 , 3 ) ;
helpers . doKeys ( 'd' ) ;
eq ( 'p' , cm . getValue ( ) ) ;
} , { value : 'abcd\nefgh\nijkl\nmnop' } ) ;
testVim ( 'o_visual_block' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( '<C-v>' , '3' , 'j' , 'l' , 'l' , 'o' ) ;
eqCursorPos ( Pos ( 3 , 3 ) , vim . sel . anchor ) ;
eqCursorPos ( Pos ( 0 , 1 ) , vim . sel . head ) ;
helpers . doKeys ( 'O' ) ;
eqCursorPos ( Pos ( 3 , 1 ) , vim . sel . anchor ) ;
eqCursorPos ( Pos ( 0 , 3 ) , vim . sel . head ) ;
helpers . doKeys ( 'o' ) ;
eqCursorPos ( Pos ( 0 , 3 ) , vim . sel . anchor ) ;
eqCursorPos ( Pos ( 3 , 1 ) , vim . sel . head ) ;
} , { value : 'abcd\nefgh\nijkl\nmnop' } ) ;
testVim ( 'changeCase_visual' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'v' , 'l' , 'l' ) ;
helpers . doKeys ( 'U' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
helpers . doKeys ( 'v' , 'l' , 'l' ) ;
helpers . doKeys ( 'u' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
helpers . doKeys ( 'l' , 'l' , 'l' , '.' ) ;
helpers . assertCursorAt ( 0 , 3 ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'q' , 'a' , 'v' , 'j' , 'U' , 'q' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
helpers . doKeys ( 'j' , '@' , 'a' ) ;
helpers . assertCursorAt ( 1 , 0 ) ;
cm . setCursor ( 3 , 0 ) ;
helpers . doKeys ( 'V' , 'U' , 'j' , '.' ) ;
eq ( 'ABCDEF\nGHIJKL\nMnopq\nSHORT LINE\nLONG LINE OF TEXT' , cm . getValue ( ) ) ;
} , { value : 'abcdef\nghijkl\nmnopq\nshort line\nlong line of text' } ) ;
testVim ( 'changeCase_visual_block' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 1 ) ;
helpers . doKeys ( '<C-v>' , 'k' , 'k' , 'h' , 'U' ) ;
eq ( 'ABcdef\nGHijkl\nMNopq\nfoo' , cm . getValue ( ) ) ;
cm . setCursor ( 0 , 2 ) ;
helpers . doKeys ( '.' ) ;
eq ( 'ABCDef\nGHIJkl\nMNOPq\nfoo' , cm . getValue ( ) ) ;
// check when last line is shorter.
cm . setCursor ( 2 , 2 ) ;
helpers . doKeys ( '.' ) ;
eq ( 'ABCDef\nGHIJkl\nMNOPq\nfoO' , cm . getValue ( ) ) ;
} , { value : 'abcdef\nghijkl\nmnopq\nfoo' } ) ;
testVim ( 'visual_paste' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'v' , 'l' , 'l' , 'y' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
helpers . doKeys ( '3' , 'l' , 'j' , 'v' , 'l' , 'p' ) ;
helpers . assertCursorAt ( 1 , 5 ) ;
eq ( 'this is a\nunithitest for visual paste' , cm . getValue ( ) ) ;
cm . setCursor ( 0 , 0 ) ;
// in case of pasting whole line
helpers . doKeys ( 'y' , 'y' ) ;
cm . setCursor ( 1 , 6 ) ;
helpers . doKeys ( 'v' , 'l' , 'l' , 'l' , 'p' ) ;
helpers . assertCursorAt ( 2 , 0 ) ;
eq ( 'this is a\nunithi\nthis is a\n for visual paste' , cm . getValue ( ) ) ;
} , { value : 'this is a\nunit test for visual paste' } ) ;
// This checks the contents of the register used to paste the text
testVim ( 'v_paste_from_register' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '"' , 'a' , 'y' , 'w' ) ;
cm . setCursor ( 1 , 0 ) ;
helpers . doKeys ( 'v' , 'p' ) ;
cm . openDialog = helpers . fakeOpenDialog ( 'registers' ) ;
cm . openNotification = helpers . fakeOpenNotification ( function ( text ) {
is ( /a\s+register/ . test ( text ) ) ;
} ) ;
} , { value : 'register contents\nare not erased' } ) ;
testVim ( 'S_normal' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( 'j' , 'S' ) ;
helpers . doKeys ( '<Esc>' ) ;
helpers . assertCursorAt ( 1 , 1 ) ;
eq ( 'aa{\n \ncc' , cm . getValue ( ) ) ;
helpers . doKeys ( 'j' , 'S' ) ;
eq ( 'aa{\n \n ' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 2 , 2 ) ;
helpers . doKeys ( '<Esc>' ) ;
helpers . doKeys ( 'd' , 'd' , 'd' , 'd' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
helpers . doKeys ( 'S' ) ;
is ( vim . insertMode ) ;
eq ( '' , cm . getValue ( ) ) ;
} , { value : 'aa{\nbb\ncc' } ) ;
testVim ( 'blockwise_paste' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '<C-v>' , '3' , 'j' , 'l' , 'y' ) ;
cm . setCursor ( 0 , 2 ) ;
// paste one char after the current cursor position
helpers . doKeys ( 'p' ) ;
eq ( 'helhelo\nworwold\nfoofo\nbarba' , cm . getValue ( ) ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'v' , '4' , 'l' , 'y' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '<C-v>' , '3' , 'j' , 'p' ) ;
eq ( 'helheelhelo\norwold\noofo\narba' , cm . getValue ( ) ) ;
} , { value : 'hello\nworld\nfoo\nbar' } ) ;
testVim ( 'blockwise_paste_long/short_line' , function ( cm , vim , helpers ) {
// extend short lines in case of different line lengths.
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '<C-v>' , 'j' , 'j' , 'y' ) ;
cm . setCursor ( 0 , 3 ) ;
helpers . doKeys ( 'p' ) ;
eq ( 'hellho\nfoo f\nbar b' , cm . getValue ( ) ) ;
} , { value : 'hello\nfoo\nbar' } ) ;
testVim ( 'blockwise_paste_cut_paste' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '<C-v>' , '2' , 'j' , 'x' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'P' ) ;
eq ( 'cut\nand\npaste\nme' , cm . getValue ( ) ) ;
} , { value : 'cut\nand\npaste\nme' } ) ;
testVim ( 'blockwise_paste_from_register' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '<C-v>' , '2' , 'j' , '"' , 'a' , 'y' ) ;
cm . setCursor ( 0 , 3 ) ;
helpers . doKeys ( '"' , 'a' , 'p' ) ;
eq ( 'foobfar\nhellho\nworlwd' , cm . getValue ( ) ) ;
} , { value : 'foobar\nhello\nworld' } ) ;
testVim ( 'blockwise_paste_last_line' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '<C-v>' , '2' , 'j' , 'l' , 'y' ) ;
cm . setCursor ( 3 , 0 ) ;
helpers . doKeys ( 'p' ) ;
eq ( 'cut\nand\npaste\nmcue\n an\n pa' , cm . getValue ( ) ) ;
} , { value : 'cut\nand\npaste\nme' } ) ;
testVim ( 'S_visual' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( 'v' , 'j' , 'S' ) ;
helpers . doKeys ( '<Esc>' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
eq ( '\ncc' , cm . getValue ( ) ) ;
} , { value : 'aa\nbb\ncc' } ) ;
testVim ( 'd_/' , function ( cm , vim , helpers ) {
cm . openDialog = helpers . fakeOpenDialog ( 'match' ) ;
helpers . doKeys ( '2' , 'd' , '/' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
eq ( 'match \n next' , cm . getValue ( ) ) ;
cm . openDialog = helpers . fakeOpenDialog ( '2' ) ;
helpers . doKeys ( 'd' , ':' ) ;
// TODO eq(' next', cm.getValue());
} , { value : 'text match match \n next' } ) ;
testVim ( '/ and n/N' , function ( cm , vim , helpers ) {
cm . openDialog = helpers . fakeOpenDialog ( 'match' ) ;
helpers . doKeys ( '/' ) ;
helpers . assertCursorAt ( 0 , 11 ) ;
helpers . doKeys ( 'n' ) ;
helpers . assertCursorAt ( 1 , 6 ) ;
helpers . doKeys ( 'N' ) ;
helpers . assertCursorAt ( 0 , 11 ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '2' , '/' ) ;
helpers . assertCursorAt ( 1 , 6 ) ;
} , { value : 'match nope match \n nope Match' } ) ;
2020-10-02 13:05:50 +02:00
testVim ( '/ and gn selects the appropriate word' , function ( cm , vim , helpers ) {
cm . openDialog = helpers . fakeOpenDialog ( 'match' ) ;
helpers . doKeys ( '/' ) ;
helpers . assertCursorAt ( 0 , 11 ) ;
// gn should highlight the the current word while it is within a match.
// gn when cursor is in beginning of match
helpers . doKeys ( 'gn' , '<Esc>' ) ;
helpers . assertCursorAt ( 0 , 15 ) ;
// gn when cursor is at end of match
helpers . doKeys ( 'gn' , '<Esc>' ) ;
helpers . doKeys ( '<Esc>' ) ;
helpers . assertCursorAt ( 0 , 15 ) ;
// consecutive gns should extend the selection
helpers . doKeys ( 'gn' ) ;
helpers . assertCursorAt ( 0 , 16 ) ;
helpers . doKeys ( 'gn' ) ;
helpers . assertCursorAt ( 1 , 11 ) ;
// we should have selected the second and third "match"
helpers . doKeys ( 'd' ) ;
eq ( 'match nope ' , cm . getValue ( ) ) ;
} , { value : 'match nope match \n nope Match' } ) ;
testVim ( '/ and gN selects the appropriate word' , function ( cm , vim , helpers ) {
cm . openDialog = helpers . fakeOpenDialog ( 'match' ) ;
helpers . doKeys ( '/' ) ;
helpers . assertCursorAt ( 0 , 11 ) ;
// gN when cursor is at beginning of match
helpers . doKeys ( 'gN' , '<Esc>' ) ;
helpers . assertCursorAt ( 0 , 11 ) ;
// gN when cursor is at end of match
helpers . doKeys ( 'e' , 'gN' , '<Esc>' ) ;
helpers . assertCursorAt ( 0 , 11 ) ;
// consecutive gNs should extend the selection
helpers . doKeys ( 'gN' ) ;
helpers . assertCursorAt ( 0 , 11 ) ;
helpers . doKeys ( 'gN' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
// we should have selected the first and second "match"
helpers . doKeys ( 'd' ) ;
eq ( ' \n nope Match' , cm . getValue ( ) ) ;
} , { value : 'match nope match \n nope Match' } )
testVim ( '/ and gn with an associated operator' , function ( cm , vim , helpers ) {
cm . openDialog = helpers . fakeOpenDialog ( 'match' ) ;
helpers . doKeys ( '/' ) ;
helpers . assertCursorAt ( 0 , 11 ) ;
helpers . doKeys ( 'c' , 'gn' , 'changed' , '<Esc>' ) ;
// change the current match.
eq ( 'match nope changed \n nope Match' , cm . getValue ( ) ) ;
// change the next match.
helpers . doKeys ( '.' ) ;
eq ( 'match nope changed \n nope changed' , cm . getValue ( ) ) ;
// change the final match.
helpers . doKeys ( '.' ) ;
eq ( 'changed nope changed \n nope changed' , cm . getValue ( ) ) ;
} , { value : 'match nope match \n nope Match' } ) ;
testVim ( '/ and gN with an associated operator' , function ( cm , vim , helpers ) {
cm . openDialog = helpers . fakeOpenDialog ( 'match' ) ;
helpers . doKeys ( '/' ) ;
helpers . assertCursorAt ( 0 , 11 ) ;
helpers . doKeys ( 'c' , 'gN' , 'changed' , '<Esc>' ) ;
// change the current match.
eq ( 'match nope changed \n nope Match' , cm . getValue ( ) ) ;
// change the next match.
helpers . doKeys ( '.' ) ;
eq ( 'changed nope changed \n nope Match' , cm . getValue ( ) ) ;
// change the final match.
helpers . doKeys ( '.' ) ;
eq ( 'changed nope changed \n nope changed' , cm . getValue ( ) ) ;
} , { value : 'match nope match \n nope Match' } ) ;
2019-07-28 14:57:52 +02:00
testVim ( '/_case' , function ( cm , vim , helpers ) {
cm . openDialog = helpers . fakeOpenDialog ( 'Match' ) ;
helpers . doKeys ( '/' ) ;
helpers . assertCursorAt ( 1 , 6 ) ;
} , { value : 'match nope match \n nope Match' } ) ;
testVim ( '/_2_pcre' , function ( cm , vim , helpers ) {
CodeMirror . Vim . setOption ( 'pcre' , true ) ;
cm . openDialog = helpers . fakeOpenDialog ( '(word){2}' ) ;
helpers . doKeys ( '/' ) ;
helpers . assertCursorAt ( 1 , 9 ) ;
helpers . doKeys ( 'n' ) ;
helpers . assertCursorAt ( 2 , 1 ) ;
} , { value : 'word\n another wordword\n wordwordword\n' } ) ;
testVim ( '/_2_nopcre' , function ( cm , vim , helpers ) {
CodeMirror . Vim . setOption ( 'pcre' , false ) ;
cm . openDialog = helpers . fakeOpenDialog ( '\\(word\\)\\{2}' ) ;
helpers . doKeys ( '/' ) ;
helpers . assertCursorAt ( 1 , 9 ) ;
helpers . doKeys ( 'n' ) ;
helpers . assertCursorAt ( 2 , 1 ) ;
} , { value : 'word\n another wordword\n wordwordword\n' } ) ;
testVim ( '/_nongreedy' , function ( cm , vim , helpers ) {
cm . openDialog = helpers . fakeOpenDialog ( 'aa' ) ;
helpers . doKeys ( '/' ) ;
helpers . assertCursorAt ( 0 , 4 ) ;
helpers . doKeys ( 'n' ) ;
helpers . assertCursorAt ( 1 , 3 ) ;
helpers . doKeys ( 'n' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
} , { value : 'aaa aa \n a aa' } ) ;
testVim ( '?_nongreedy' , function ( cm , vim , helpers ) {
cm . openDialog = helpers . fakeOpenDialog ( 'aa' ) ;
helpers . doKeys ( '?' ) ;
helpers . assertCursorAt ( 1 , 3 ) ;
helpers . doKeys ( 'n' ) ;
helpers . assertCursorAt ( 0 , 4 ) ;
helpers . doKeys ( 'n' ) ;
2020-10-02 13:05:50 +02:00
helpers . assertCursorAt ( 0 , 1 ) ;
2019-07-28 14:57:52 +02:00
} , { value : 'aaa aa \n a aa' } ) ;
testVim ( '/_greedy' , function ( cm , vim , helpers ) {
cm . openDialog = helpers . fakeOpenDialog ( 'a+' ) ;
helpers . doKeys ( '/' ) ;
helpers . assertCursorAt ( 0 , 4 ) ;
helpers . doKeys ( 'n' ) ;
helpers . assertCursorAt ( 1 , 1 ) ;
helpers . doKeys ( 'n' ) ;
helpers . assertCursorAt ( 1 , 3 ) ;
helpers . doKeys ( 'n' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
} , { value : 'aaa aa \n a aa' } ) ;
testVim ( '?_greedy' , function ( cm , vim , helpers ) {
cm . openDialog = helpers . fakeOpenDialog ( 'a+' ) ;
helpers . doKeys ( '?' ) ;
helpers . assertCursorAt ( 1 , 3 ) ;
helpers . doKeys ( 'n' ) ;
helpers . assertCursorAt ( 1 , 1 ) ;
helpers . doKeys ( 'n' ) ;
helpers . assertCursorAt ( 0 , 4 ) ;
helpers . doKeys ( 'n' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
} , { value : 'aaa aa \n a aa' } ) ;
testVim ( '/_greedy_0_or_more' , function ( cm , vim , helpers ) {
cm . openDialog = helpers . fakeOpenDialog ( 'a*' ) ;
helpers . doKeys ( '/' ) ;
helpers . assertCursorAt ( 0 , 3 ) ;
helpers . doKeys ( 'n' ) ;
helpers . assertCursorAt ( 0 , 4 ) ;
helpers . doKeys ( 'n' ) ;
helpers . assertCursorAt ( 0 , 5 ) ;
helpers . doKeys ( 'n' ) ;
helpers . assertCursorAt ( 1 , 0 ) ;
helpers . doKeys ( 'n' ) ;
helpers . assertCursorAt ( 1 , 1 ) ;
helpers . doKeys ( 'n' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
} , { value : 'aaa aa\n aa' } ) ;
testVim ( '?_greedy_0_or_more' , function ( cm , vim , helpers ) {
cm . openDialog = helpers . fakeOpenDialog ( 'a*' ) ;
helpers . doKeys ( '?' ) ;
helpers . assertCursorAt ( 1 , 1 ) ;
helpers . doKeys ( 'n' ) ;
helpers . assertCursorAt ( 0 , 5 ) ;
helpers . doKeys ( 'n' ) ;
helpers . assertCursorAt ( 0 , 3 ) ;
helpers . doKeys ( 'n' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
} , { value : 'aaa aa\n aa' } ) ;
testVim ( '? and n/N' , function ( cm , vim , helpers ) {
cm . openDialog = helpers . fakeOpenDialog ( 'match' ) ;
helpers . doKeys ( '?' ) ;
helpers . assertCursorAt ( 1 , 6 ) ;
helpers . doKeys ( 'n' ) ;
helpers . assertCursorAt ( 0 , 11 ) ;
helpers . doKeys ( 'N' ) ;
helpers . assertCursorAt ( 1 , 6 ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '2' , '?' ) ;
helpers . assertCursorAt ( 0 , 11 ) ;
} , { value : 'match nope match \n nope Match' } ) ;
2020-10-02 13:05:50 +02:00
testVim ( '? and gn selects the appropriate word' , function ( cm , vim , helpers ) {
cm . openDialog = helpers . fakeOpenDialog ( 'match' ) ;
helpers . doKeys ( '?' , 'n' ) ;
helpers . assertCursorAt ( 0 , 11 ) ;
// gn should highlight the the current word while it is within a match.
// gn when cursor is in beginning of match
helpers . doKeys ( 'gn' , '<Esc>' ) ;
helpers . assertCursorAt ( 0 , 11 ) ;
// gn when cursor is at end of match
helpers . doKeys ( 'e' , 'gn' , '<Esc>' ) ;
helpers . assertCursorAt ( 0 , 11 ) ;
// consecutive gns should extend the selection
helpers . doKeys ( 'gn' ) ;
helpers . assertCursorAt ( 0 , 11 ) ;
helpers . doKeys ( 'gn' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
// we should have selected the first and second "match"
helpers . doKeys ( 'd' ) ;
eq ( ' \n nope Match' , cm . getValue ( ) ) ;
} , { value : 'match nope match \n nope Match' } ) ;
testVim ( '? and gN selects the appropriate word' , function ( cm , vim , helpers ) {
cm . openDialog = helpers . fakeOpenDialog ( 'match' ) ;
helpers . doKeys ( '?' , 'n' ) ;
helpers . assertCursorAt ( 0 , 11 ) ;
// gN when cursor is at beginning of match
helpers . doKeys ( 'gN' , '<Esc>' ) ;
helpers . assertCursorAt ( 0 , 15 ) ;
// gN when cursor is at end of match
helpers . doKeys ( 'gN' , '<Esc>' ) ;
helpers . assertCursorAt ( 0 , 15 ) ;
// consecutive gNs should extend the selection
helpers . doKeys ( 'gN' ) ;
helpers . assertCursorAt ( 0 , 16 ) ;
helpers . doKeys ( 'gN' ) ;
helpers . assertCursorAt ( 1 , 11 ) ;
// we should have selected the second and third "match"
helpers . doKeys ( 'd' ) ;
eq ( 'match nope ' , cm . getValue ( ) ) ;
} , { value : 'match nope match \n nope Match' } )
testVim ( '? and gn with an associated operator' , function ( cm , vim , helpers ) {
cm . openDialog = helpers . fakeOpenDialog ( 'match' ) ;
helpers . doKeys ( '?' , 'n' ) ;
helpers . assertCursorAt ( 0 , 11 ) ;
helpers . doKeys ( 'c' , 'gn' , 'changed' , '<Esc>' ) ;
// change the current match.
eq ( 'match nope changed \n nope Match' , cm . getValue ( ) ) ;
// change the next match.
helpers . doKeys ( '.' ) ;
eq ( 'changed nope changed \n nope Match' , cm . getValue ( ) ) ;
// change the final match.
helpers . doKeys ( '.' ) ;
eq ( 'changed nope changed \n nope changed' , cm . getValue ( ) ) ;
} , { value : 'match nope match \n nope Match' } ) ;
testVim ( '? and gN with an associated operator' , function ( cm , vim , helpers ) {
cm . openDialog = helpers . fakeOpenDialog ( 'match' ) ;
helpers . doKeys ( '?' , 'n' ) ;
helpers . assertCursorAt ( 0 , 11 ) ;
helpers . doKeys ( 'c' , 'gN' , 'changed' , '<Esc>' ) ;
// change the current match.
eq ( 'match nope changed \n nope Match' , cm . getValue ( ) ) ;
// change the next match.
helpers . doKeys ( '.' ) ;
eq ( 'match nope changed \n nope changed' , cm . getValue ( ) ) ;
// change the final match.
helpers . doKeys ( '.' ) ;
eq ( 'changed nope changed \n nope changed' , cm . getValue ( ) ) ;
} , { value : 'match nope match \n nope Match' } ) ;
2019-07-28 14:57:52 +02:00
testVim ( '*' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( '*' ) ;
helpers . assertCursorAt ( 0 , 22 ) ;
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( '2' , '*' ) ;
helpers . assertCursorAt ( 1 , 8 ) ;
} , { value : 'nomatch match nomatch match \nnomatch Match' } ) ;
testVim ( '*_no_word' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '*' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
} , { value : ' \n match \n' } ) ;
testVim ( '*_symbol' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '*' ) ;
helpers . assertCursorAt ( 1 , 0 ) ;
} , { value : ' /}\n/} match \n' } ) ;
testVim ( '#' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( '#' ) ;
helpers . assertCursorAt ( 1 , 8 ) ;
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( '2' , '#' ) ;
helpers . assertCursorAt ( 0 , 22 ) ;
} , { value : 'nomatch match nomatch match \nnomatch Match' } ) ;
testVim ( '*_seek' , function ( cm , vim , helpers ) {
// Should skip over space and symbols.
cm . setCursor ( 0 , 3 ) ;
helpers . doKeys ( '*' ) ;
helpers . assertCursorAt ( 0 , 22 ) ;
} , { value : ' := match nomatch match \nnomatch Match' } ) ;
testVim ( '#' , function ( cm , vim , helpers ) {
// Should skip over space and symbols.
cm . setCursor ( 0 , 3 ) ;
helpers . doKeys ( '#' ) ;
helpers . assertCursorAt ( 1 , 8 ) ;
} , { value : ' := match nomatch match \nnomatch Match' } ) ;
testVim ( 'g*' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 8 ) ;
helpers . doKeys ( 'g' , '*' ) ;
helpers . assertCursorAt ( 0 , 18 ) ;
cm . setCursor ( 0 , 8 ) ;
helpers . doKeys ( '3' , 'g' , '*' ) ;
helpers . assertCursorAt ( 1 , 8 ) ;
} , { value : 'matches match alsoMatch\nmatchme matching' } ) ;
testVim ( 'g#' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 8 ) ;
helpers . doKeys ( 'g' , '#' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
cm . setCursor ( 0 , 8 ) ;
helpers . doKeys ( '3' , 'g' , '#' ) ;
helpers . assertCursorAt ( 1 , 0 ) ;
} , { value : 'matches match alsoMatch\nmatchme matching' } ) ;
testVim ( 'macro_insert' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'q' , 'a' , '0' , 'i' ) ;
helpers . doKeys ( 'foo' )
helpers . doKeys ( '<Esc>' ) ;
helpers . doKeys ( 'q' , '@' , 'a' ) ;
eq ( 'foofoo' , cm . getValue ( ) ) ;
} , { value : '' } ) ;
testVim ( 'macro_insert_repeat' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'q' , 'a' , '$' , 'a' ) ;
helpers . doKeys ( 'larry.' )
helpers . doKeys ( '<Esc>' ) ;
helpers . doKeys ( 'a' ) ;
helpers . doKeys ( 'curly.' )
helpers . doKeys ( '<Esc>' ) ;
helpers . doKeys ( 'q' ) ;
helpers . doKeys ( 'a' ) ;
helpers . doKeys ( 'moe.' )
helpers . doKeys ( '<Esc>' ) ;
helpers . doKeys ( '@' , 'a' ) ;
// At this point, the most recent edit should be the 2nd insert change
// inside the macro, i.e. "curly.".
helpers . doKeys ( '.' ) ;
eq ( 'larry.curly.moe.larry.curly.curly.' , cm . getValue ( ) ) ;
} , { value : '' } ) ;
testVim ( 'macro_space' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '<Space>' , '<Space>' ) ;
helpers . assertCursorAt ( 0 , 2 ) ;
helpers . doKeys ( 'q' , 'a' , '<Space>' , '<Space>' , 'q' ) ;
helpers . assertCursorAt ( 0 , 4 ) ;
helpers . doKeys ( '@' , 'a' ) ;
helpers . assertCursorAt ( 0 , 6 ) ;
helpers . doKeys ( '@' , 'a' ) ;
helpers . assertCursorAt ( 0 , 8 ) ;
} , { value : 'one line of text.' } ) ;
testVim ( 'macro_t_search' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'q' , 'a' , 't' , 'e' , 'q' ) ;
helpers . assertCursorAt ( 0 , 1 ) ;
helpers . doKeys ( 'l' , '@' , 'a' ) ;
helpers . assertCursorAt ( 0 , 6 ) ;
helpers . doKeys ( 'l' , ';' ) ;
helpers . assertCursorAt ( 0 , 12 ) ;
} , { value : 'one line of text.' } ) ;
testVim ( 'macro_f_search' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'q' , 'b' , 'f' , 'e' , 'q' ) ;
helpers . assertCursorAt ( 0 , 2 ) ;
helpers . doKeys ( '@' , 'b' ) ;
helpers . assertCursorAt ( 0 , 7 ) ;
helpers . doKeys ( ';' ) ;
helpers . assertCursorAt ( 0 , 13 ) ;
} , { value : 'one line of text.' } ) ;
testVim ( 'macro_slash_search' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'q' , 'c' ) ;
cm . openDialog = helpers . fakeOpenDialog ( 'e' ) ;
helpers . doKeys ( '/' , 'q' ) ;
helpers . assertCursorAt ( 0 , 2 ) ;
helpers . doKeys ( '@' , 'c' ) ;
helpers . assertCursorAt ( 0 , 7 ) ;
helpers . doKeys ( 'n' ) ;
helpers . assertCursorAt ( 0 , 13 ) ;
} , { value : 'one line of text.' } ) ;
testVim ( 'macro_multislash_search' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'q' , 'd' ) ;
cm . openDialog = helpers . fakeOpenDialog ( 'e' ) ;
helpers . doKeys ( '/' ) ;
cm . openDialog = helpers . fakeOpenDialog ( 't' ) ;
helpers . doKeys ( '/' , 'q' ) ;
helpers . assertCursorAt ( 0 , 12 ) ;
helpers . doKeys ( '@' , 'd' ) ;
helpers . assertCursorAt ( 0 , 15 ) ;
} , { value : 'one line of text to rule them all.' } ) ;
testVim ( 'macro_last_ex_command_register' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doEx ( 's/a/b' ) ;
helpers . doKeys ( '2' , '@' , ':' ) ;
eq ( 'bbbaa' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 2 ) ;
} , { value : 'aaaaa' } ) ;
testVim ( 'macro_last_run_macro' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'q' , 'a' , 'C' , 'a' , '<Esc>' , 'q' ) ;
helpers . doKeys ( 'q' , 'b' , 'C' , 'b' , '<Esc>' , 'q' ) ;
helpers . doKeys ( '@' , 'a' ) ;
helpers . doKeys ( 'd' , 'd' ) ;
helpers . doKeys ( '@' , '@' ) ;
eq ( 'a' , cm . getValue ( ) ) ;
} , { value : '' } ) ;
testVim ( 'macro_parens' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'q' , 'z' , 'i' ) ;
helpers . doKeys ( '(' )
helpers . doKeys ( '<Esc>' ) ;
helpers . doKeys ( 'e' , 'a' ) ;
helpers . doKeys ( ')' )
helpers . doKeys ( '<Esc>' ) ;
helpers . doKeys ( 'q' ) ;
helpers . doKeys ( 'w' , '@' , 'z' ) ;
helpers . doKeys ( 'w' , '@' , 'z' ) ;
eq ( '(see) (spot) (run)' , cm . getValue ( ) ) ;
} , { value : 'see spot run' } ) ;
testVim ( 'macro_overwrite' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'q' , 'z' , '0' , 'i' ) ;
helpers . doKeys ( 'I ' )
helpers . doKeys ( '<Esc>' ) ;
helpers . doKeys ( 'q' ) ;
helpers . doKeys ( 'e' ) ;
// Now replace the macro with something else.
helpers . doKeys ( 'q' , 'z' , 'a' ) ;
helpers . doKeys ( '.' )
helpers . doKeys ( '<Esc>' ) ;
helpers . doKeys ( 'q' ) ;
helpers . doKeys ( 'e' , '@' , 'z' ) ;
helpers . doKeys ( 'e' , '@' , 'z' ) ;
eq ( 'I see. spot. run.' , cm . getValue ( ) ) ;
} , { value : 'see spot run' } ) ;
testVim ( 'macro_search_f' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'q' , 'a' , 'f' , ' ' ) ;
helpers . assertCursorAt ( 0 , 3 ) ;
helpers . doKeys ( 'q' , '0' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
helpers . doKeys ( '@' , 'a' ) ;
helpers . assertCursorAt ( 0 , 3 ) ;
} , { value : 'The quick brown fox jumped over the lazy dog.' } ) ;
testVim ( 'macro_search_2f' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'q' , 'a' , '2' , 'f' , ' ' ) ;
helpers . assertCursorAt ( 0 , 9 ) ;
helpers . doKeys ( 'q' , '0' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
helpers . doKeys ( '@' , 'a' ) ;
helpers . assertCursorAt ( 0 , 9 ) ;
} , { value : 'The quick brown fox jumped over the lazy dog.' } ) ;
testVim ( 'macro_yank_tick' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
// Start recording a macro into the \' register.
helpers . doKeys ( 'q' , '\'' ) ;
helpers . doKeys ( 'y' , '<Right>' , '<Right>' , '<Right>' , '<Right>' , 'p' ) ;
helpers . assertCursorAt ( 0 , 4 ) ;
eq ( 'the tex parrot' , cm . getValue ( ) ) ;
} , { value : 'the ex parrot' } ) ;
testVim ( 'yank_register' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '"' , 'a' , 'y' , 'y' ) ;
helpers . doKeys ( 'j' , '"' , 'b' , 'y' , 'y' ) ;
cm . openDialog = helpers . fakeOpenDialog ( 'registers' ) ;
cm . openNotification = helpers . fakeOpenNotification ( function ( text ) {
is ( /a\s+foo/ . test ( text ) ) ;
is ( /b\s+bar/ . test ( text ) ) ;
} ) ;
helpers . doKeys ( ':' ) ;
} , { value : 'foo\nbar' } ) ;
testVim ( 'yank_visual_block' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( '<C-v>' , 'l' , 'j' , '"' , 'a' , 'y' ) ;
cm . openNotification = helpers . fakeOpenNotification ( function ( text ) {
is ( /a\s+oo\nar/ . test ( text ) ) ;
} ) ;
helpers . doKeys ( ':' ) ;
} , { value : 'foo\nbar' } ) ;
testVim ( 'yank_append_line_to_line_register' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '"' , 'a' , 'y' , 'y' ) ;
helpers . doKeys ( 'j' , '"' , 'A' , 'y' , 'y' ) ;
cm . openDialog = helpers . fakeOpenDialog ( 'registers' ) ;
cm . openNotification = helpers . fakeOpenNotification ( function ( text ) {
is ( /a\s+foo\nbar/ . test ( text ) ) ;
is ( /"\s+foo\nbar/ . test ( text ) ) ;
} ) ;
helpers . doKeys ( ':' ) ;
} , { value : 'foo\nbar' } ) ;
testVim ( 'yank_append_word_to_word_register' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '"' , 'a' , 'y' , 'w' ) ;
helpers . doKeys ( 'j' , '"' , 'A' , 'y' , 'w' ) ;
cm . openDialog = helpers . fakeOpenDialog ( 'registers' ) ;
cm . openNotification = helpers . fakeOpenNotification ( function ( text ) {
is ( /a\s+foobar/ . test ( text ) ) ;
is ( /"\s+foobar/ . test ( text ) ) ;
} ) ;
helpers . doKeys ( ':' ) ;
} , { value : 'foo\nbar' } ) ;
testVim ( 'yank_append_line_to_word_register' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '"' , 'a' , 'y' , 'w' ) ;
helpers . doKeys ( 'j' , '"' , 'A' , 'y' , 'y' ) ;
cm . openDialog = helpers . fakeOpenDialog ( 'registers' ) ;
cm . openNotification = helpers . fakeOpenNotification ( function ( text ) {
is ( /a\s+foo\nbar/ . test ( text ) ) ;
is ( /"\s+foo\nbar/ . test ( text ) ) ;
} ) ;
helpers . doKeys ( ':' ) ;
} , { value : 'foo\nbar' } ) ;
testVim ( 'yank_append_word_to_line_register' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '"' , 'a' , 'y' , 'y' ) ;
helpers . doKeys ( 'j' , '"' , 'A' , 'y' , 'w' ) ;
cm . openDialog = helpers . fakeOpenDialog ( 'registers' ) ;
cm . openNotification = helpers . fakeOpenNotification ( function ( text ) {
is ( /a\s+foo\nbar/ . test ( text ) ) ;
is ( /"\s+foo\nbar/ . test ( text ) ) ;
} ) ;
helpers . doKeys ( ':' ) ;
} , { value : 'foo\nbar' } ) ;
2020-10-02 13:05:50 +02:00
testVim ( 'black_hole_register' , function ( cm , vim , helpers ) {
helpers . doKeys ( 'g' , 'g' , 'y' , 'G' ) ;
var registersText ;
cm . openDialog = helpers . fakeOpenDialog ( 'registers' ) ;
cm . openNotification = helpers . fakeOpenNotification ( function ( text ) {
registersText = text ;
} ) ;
helpers . doKeys ( ':' ) ;
helpers . doKeys ( '"' , '_' , 'd' , 'G' ) ;
cm . openDialog = helpers . fakeOpenDialog ( 'registers' ) ;
cm . openNotification = helpers . fakeOpenNotification ( function ( text ) {
eq ( registersText , text , 'One or more registers were modified' ) ;
} ) ;
helpers . doKeys ( ':' ) ;
helpers . doKeys ( '"' , '_' , 'p' ) ;
eq ( '' , cm . getValue ( ) ) ;
} , { value : 'foo\nbar' } ) ;
2019-07-28 14:57:52 +02:00
testVim ( 'macro_register' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'q' , 'a' , 'i' ) ;
helpers . doKeys ( 'gangnam' )
helpers . doKeys ( '<Esc>' ) ;
helpers . doKeys ( 'q' ) ;
helpers . doKeys ( 'q' , 'b' , 'o' ) ;
helpers . doKeys ( 'style' )
helpers . doKeys ( '<Esc>' ) ;
helpers . doKeys ( 'q' ) ;
cm . openDialog = helpers . fakeOpenDialog ( 'registers' ) ;
cm . openNotification = helpers . fakeOpenNotification ( function ( text ) {
is ( /a\s+i/ . test ( text ) ) ;
is ( /b\s+o/ . test ( text ) ) ;
} ) ;
helpers . doKeys ( ':' ) ;
} , { value : '' } ) ;
testVim ( '._register' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'i' ) ;
helpers . doKeys ( 'foo' )
helpers . doKeys ( '<Esc>' ) ;
cm . openDialog = helpers . fakeOpenDialog ( 'registers' ) ;
cm . openNotification = helpers . fakeOpenNotification ( function ( text ) {
is ( /\.\s+foo/ . test ( text ) ) ;
} ) ;
helpers . doKeys ( ':' ) ;
} , { value : '' } ) ;
testVim ( ':_register' , function ( cm , vim , helpers ) {
helpers . doEx ( 'bar' ) ;
cm . openDialog = helpers . fakeOpenDialog ( 'registers' ) ;
cm . openNotification = helpers . fakeOpenNotification ( function ( text ) {
is ( /:\s+bar/ . test ( text ) ) ;
} ) ;
helpers . doKeys ( ':' ) ;
} , { value : '' } ) ;
testVim ( 'search_register_escape' , function ( cm , vim , helpers ) {
// Check that the register is restored if the user escapes rather than confirms.
cm . openDialog = helpers . fakeOpenDialog ( 'waldo' ) ;
helpers . doKeys ( '/' ) ;
var onKeyDown ;
var onKeyUp ;
var KEYCODES = {
f : 70 ,
o : 79 ,
Esc : 27
} ;
cm . openDialog = function ( template , callback , options ) {
onKeyDown = options . onKeyDown ;
onKeyUp = options . onKeyUp ;
} ;
var close = function ( ) { } ;
helpers . doKeys ( '/' ) ;
// Fake some keyboard events coming in.
onKeyDown ( { keyCode : KEYCODES . f } , '' , close ) ;
onKeyUp ( { keyCode : KEYCODES . f } , '' , close ) ;
onKeyDown ( { keyCode : KEYCODES . o } , 'f' , close ) ;
onKeyUp ( { keyCode : KEYCODES . o } , 'f' , close ) ;
onKeyDown ( { keyCode : KEYCODES . o } , 'fo' , close ) ;
onKeyUp ( { keyCode : KEYCODES . o } , 'fo' , close ) ;
onKeyDown ( { keyCode : KEYCODES . Esc } , 'foo' , close ) ;
cm . openDialog = helpers . fakeOpenDialog ( 'registers' ) ;
cm . openNotification = helpers . fakeOpenNotification ( function ( text ) {
is ( /waldo/ . test ( text ) ) ;
is ( ! /foo/ . test ( text ) ) ;
} ) ;
helpers . doKeys ( ':' ) ;
} , { value : '' } ) ;
testVim ( 'search_register' , function ( cm , vim , helpers ) {
cm . openDialog = helpers . fakeOpenDialog ( 'foo' ) ;
helpers . doKeys ( '/' ) ;
cm . openDialog = helpers . fakeOpenDialog ( 'registers' ) ;
cm . openNotification = helpers . fakeOpenNotification ( function ( text ) {
is ( /\/\s+foo/ . test ( text ) ) ;
} ) ;
helpers . doKeys ( ':' ) ;
} , { value : '' } ) ;
testVim ( 'search_history' , function ( cm , vim , helpers ) {
cm . openDialog = helpers . fakeOpenDialog ( 'this' ) ;
helpers . doKeys ( '/' ) ;
cm . openDialog = helpers . fakeOpenDialog ( 'checks' ) ;
helpers . doKeys ( '/' ) ;
cm . openDialog = helpers . fakeOpenDialog ( 'search' ) ;
helpers . doKeys ( '/' ) ;
cm . openDialog = helpers . fakeOpenDialog ( 'history' ) ;
helpers . doKeys ( '/' ) ;
cm . openDialog = helpers . fakeOpenDialog ( 'checks' ) ;
helpers . doKeys ( '/' ) ;
var onKeyDown ;
var onKeyUp ;
var query = '' ;
var keyCodes = {
Up : 38 ,
Down : 40
} ;
cm . openDialog = function ( template , callback , options ) {
onKeyUp = options . onKeyUp ;
onKeyDown = options . onKeyDown ;
} ;
var close = function ( newVal ) {
if ( typeof newVal == 'string' ) query = newVal ;
}
helpers . doKeys ( '/' ) ;
onKeyDown ( { keyCode : keyCodes . Up } , query , close ) ;
onKeyUp ( { keyCode : keyCodes . Up } , query , close ) ;
eq ( query , 'checks' ) ;
onKeyDown ( { keyCode : keyCodes . Up } , query , close ) ;
onKeyUp ( { keyCode : keyCodes . Up } , query , close ) ;
eq ( query , 'history' ) ;
onKeyDown ( { keyCode : keyCodes . Up } , query , close ) ;
onKeyUp ( { keyCode : keyCodes . Up } , query , close ) ;
eq ( query , 'search' ) ;
onKeyDown ( { keyCode : keyCodes . Up } , query , close ) ;
onKeyUp ( { keyCode : keyCodes . Up } , query , close ) ;
eq ( query , 'this' ) ;
onKeyDown ( { keyCode : keyCodes . Down } , query , close ) ;
onKeyUp ( { keyCode : keyCodes . Down } , query , close ) ;
eq ( query , 'search' ) ;
} , { value : '' } ) ;
testVim ( 'exCommand_history' , function ( cm , vim , helpers ) {
cm . openDialog = helpers . fakeOpenDialog ( 'registers' ) ;
helpers . doKeys ( ':' ) ;
cm . openDialog = helpers . fakeOpenDialog ( 'sort' ) ;
helpers . doKeys ( ':' ) ;
cm . openDialog = helpers . fakeOpenDialog ( 'map' ) ;
helpers . doKeys ( ':' ) ;
cm . openDialog = helpers . fakeOpenDialog ( 'invalid' ) ;
helpers . doKeys ( ':' ) ;
var onKeyDown ;
var onKeyUp ;
var input = '' ;
var keyCodes = {
Up : 38 ,
Down : 40 ,
s : 115
} ;
cm . openDialog = function ( template , callback , options ) {
onKeyUp = options . onKeyUp ;
onKeyDown = options . onKeyDown ;
} ;
var close = function ( newVal ) {
if ( typeof newVal == 'string' ) input = newVal ;
}
helpers . doKeys ( ':' ) ;
onKeyDown ( { keyCode : keyCodes . Up } , input , close ) ;
eq ( input , 'invalid' ) ;
onKeyDown ( { keyCode : keyCodes . Up } , input , close ) ;
eq ( input , 'map' ) ;
onKeyDown ( { keyCode : keyCodes . Up } , input , close ) ;
eq ( input , 'sort' ) ;
onKeyDown ( { keyCode : keyCodes . Up } , input , close ) ;
eq ( input , 'registers' ) ;
onKeyDown ( { keyCode : keyCodes . s } , '' , close ) ;
input = 's' ;
onKeyDown ( { keyCode : keyCodes . Up } , input , close ) ;
eq ( input , 'sort' ) ;
} , { value : '' } ) ;
testVim ( 'search_clear' , function ( cm , vim , helpers ) {
var onKeyDown ;
var input = '' ;
var keyCodes = {
Ctrl : 17 ,
u : 85
} ;
cm . openDialog = function ( template , callback , options ) {
onKeyDown = options . onKeyDown ;
} ;
var close = function ( newVal ) {
if ( typeof newVal == 'string' ) input = newVal ;
}
helpers . doKeys ( '/' ) ;
input = 'foo' ;
onKeyDown ( { keyCode : keyCodes . Ctrl } , input , close ) ;
onKeyDown ( { keyCode : keyCodes . u , ctrlKey : true } , input , close ) ;
eq ( input , '' ) ;
} ) ;
testVim ( 'exCommand_clear' , function ( cm , vim , helpers ) {
var onKeyDown ;
var input = '' ;
var keyCodes = {
Ctrl : 17 ,
u : 85
} ;
cm . openDialog = function ( template , callback , options ) {
onKeyDown = options . onKeyDown ;
} ;
var close = function ( newVal ) {
if ( typeof newVal == 'string' ) input = newVal ;
}
helpers . doKeys ( ':' ) ;
input = 'foo' ;
onKeyDown ( { keyCode : keyCodes . Ctrl } , input , close ) ;
onKeyDown ( { keyCode : keyCodes . u , ctrlKey : true } , input , close ) ;
eq ( input , '' ) ;
} ) ;
testVim ( '.' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '2' , 'd' , 'w' ) ;
helpers . doKeys ( '.' ) ;
eq ( '5 6' , cm . getValue ( ) ) ;
} , { value : '1 2 3 4 5 6' } ) ;
testVim ( '._repeat' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '2' , 'd' , 'w' ) ;
helpers . doKeys ( '3' , '.' ) ;
eq ( '6' , cm . getValue ( ) ) ;
} , { value : '1 2 3 4 5 6' } ) ;
testVim ( '._insert' , function ( cm , vim , helpers ) {
helpers . doKeys ( 'i' ) ;
helpers . doKeys ( 'test' )
helpers . doKeys ( '<Esc>' ) ;
helpers . doKeys ( '.' ) ;
eq ( 'testestt' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 6 ) ;
helpers . doKeys ( 'O' ) ;
helpers . doKeys ( 'xyz' )
helpers . doInsertModeKeys ( 'Backspace' ) ;
helpers . doInsertModeKeys ( 'Down' ) ;
helpers . doKeys ( '<Esc>' ) ;
helpers . doKeys ( '.' ) ;
eq ( 'xy\nxy\ntestestt' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 1 , 1 ) ;
} , { value : '' } ) ;
testVim ( '._insert_repeat' , function ( cm , vim , helpers ) {
helpers . doKeys ( 'i' ) ;
helpers . doKeys ( 'test' )
cm . setCursor ( 0 , 4 ) ;
helpers . doKeys ( '<Esc>' ) ;
helpers . doKeys ( '2' , '.' ) ;
eq ( 'testesttestt' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 10 ) ;
} , { value : '' } ) ;
testVim ( '._repeat_insert' , function ( cm , vim , helpers ) {
helpers . doKeys ( '3' , 'i' ) ;
helpers . doKeys ( 'te' )
cm . setCursor ( 0 , 2 ) ;
helpers . doKeys ( '<Esc>' ) ;
helpers . doKeys ( '.' ) ;
eq ( 'tetettetetee' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 10 ) ;
} , { value : '' } ) ;
testVim ( '._insert_o' , function ( cm , vim , helpers ) {
helpers . doKeys ( 'o' ) ;
helpers . doKeys ( 'z' )
cm . setCursor ( 1 , 1 ) ;
helpers . doKeys ( '<Esc>' ) ;
helpers . doKeys ( '.' ) ;
eq ( '\nz\nz' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 2 , 0 ) ;
} , { value : '' } ) ;
testVim ( '._insert_o_repeat' , function ( cm , vim , helpers ) {
helpers . doKeys ( 'o' ) ;
helpers . doKeys ( 'z' )
helpers . doKeys ( '<Esc>' ) ;
cm . setCursor ( 1 , 0 ) ;
helpers . doKeys ( '2' , '.' ) ;
eq ( '\nz\nz\nz' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 3 , 0 ) ;
} , { value : '' } ) ;
testVim ( '._insert_o_indent' , function ( cm , vim , helpers ) {
helpers . doKeys ( 'o' ) ;
helpers . doKeys ( 'z' )
helpers . doKeys ( '<Esc>' ) ;
cm . setCursor ( 1 , 2 ) ;
helpers . doKeys ( '.' ) ;
eq ( '{\n z\n z' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 2 , 2 ) ;
} , { value : '{' } ) ;
testVim ( '._insert_cw' , function ( cm , vim , helpers ) {
helpers . doKeys ( 'c' , 'w' ) ;
helpers . doKeys ( 'test' )
helpers . doKeys ( '<Esc>' ) ;
cm . setCursor ( 0 , 3 ) ;
helpers . doKeys ( '2' , 'l' ) ;
helpers . doKeys ( '.' ) ;
eq ( 'test test word3' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 8 ) ;
} , { value : 'word1 word2 word3' } ) ;
testVim ( '._insert_cw_repeat' , function ( cm , vim , helpers ) {
// For some reason, repeat cw in desktop VIM will does not repeat insert mode
// changes. Will conform to that behavior.
helpers . doKeys ( 'c' , 'w' ) ;
helpers . doKeys ( 'test' ) ;
helpers . doKeys ( '<Esc>' ) ;
cm . setCursor ( 0 , 4 ) ;
helpers . doKeys ( 'l' ) ;
helpers . doKeys ( '2' , '.' ) ;
eq ( 'test test' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 8 ) ;
} , { value : 'word1 word2 word3' } ) ;
testVim ( '._delete' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 5 ) ;
helpers . doKeys ( 'i' ) ;
helpers . doInsertModeKeys ( 'Backspace' ) ;
helpers . doKeys ( '<Esc>' ) ;
helpers . doKeys ( '.' ) ;
eq ( 'zace' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 1 ) ;
} , { value : 'zabcde' } ) ;
testVim ( '._delete_repeat' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 6 ) ;
helpers . doKeys ( 'i' ) ;
helpers . doInsertModeKeys ( 'Backspace' ) ;
helpers . doKeys ( '<Esc>' ) ;
helpers . doKeys ( '2' , '.' ) ;
eq ( 'zzce' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 1 ) ;
} , { value : 'zzabcde' } ) ;
testVim ( '._visual_>' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'V' , 'j' , '>' ) ;
cm . setCursor ( 2 , 0 )
helpers . doKeys ( '.' ) ;
eq ( ' 1\n 2\n 3\n 4' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 2 , 2 ) ;
} , { value : '1\n2\n3\n4' } ) ;
testVim ( '._replace_repeat' , function ( cm , vim , helpers ) {
helpers . doKeys ( 'R' ) ;
cm . replaceRange ( '123' , cm . getCursor ( ) , offsetCursor ( cm . getCursor ( ) , 0 , 3 ) ) ;
cm . setCursor ( 0 , 3 ) ;
helpers . doKeys ( '<Esc>' ) ;
helpers . doKeys ( '2' , '.' ) ;
eq ( '12123123\nabcdefg' , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 7 ) ;
cm . setCursor ( 1 , 0 ) ;
helpers . doKeys ( '.' ) ;
eq ( '12123123\n123123g' , cm . getValue ( ) ) ;
helpers . doKeys ( 'l' , '"' , '.' , 'p' ) ;
eq ( '12123123\n123123g123' , cm . getValue ( ) ) ;
} , { value : 'abcdef\nabcdefg' } ) ;
testVim ( 'f;' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'f' , 'x' ) ;
helpers . doKeys ( ';' ) ;
helpers . doKeys ( '2' , ';' ) ;
eq ( 9 , cm . getCursor ( ) . ch ) ;
} , { value : '01x3xx678x' } ) ;
testVim ( 'F;' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 8 ) ;
helpers . doKeys ( 'F' , 'x' ) ;
helpers . doKeys ( ';' ) ;
helpers . doKeys ( '2' , ';' ) ;
eq ( 2 , cm . getCursor ( ) . ch ) ;
} , { value : '01x3xx6x8x' } ) ;
testVim ( 't;' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 't' , 'x' ) ;
helpers . doKeys ( ';' ) ;
helpers . doKeys ( '2' , ';' ) ;
eq ( 8 , cm . getCursor ( ) . ch ) ;
} , { value : '01x3xx678x' } ) ;
testVim ( 'T;' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( 'T' , 'x' ) ;
helpers . doKeys ( ';' ) ;
helpers . doKeys ( '2' , ';' ) ;
eq ( 2 , cm . getCursor ( ) . ch ) ;
} , { value : '0xx3xx678x' } ) ;
testVim ( 'f,' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 6 ) ;
helpers . doKeys ( 'f' , 'x' ) ;
helpers . doKeys ( ',' ) ;
helpers . doKeys ( '2' , ',' ) ;
eq ( 2 , cm . getCursor ( ) . ch ) ;
} , { value : '01x3xx678x' } ) ;
testVim ( 'F,' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 3 ) ;
helpers . doKeys ( 'F' , 'x' ) ;
helpers . doKeys ( ',' ) ;
helpers . doKeys ( '2' , ',' ) ;
eq ( 9 , cm . getCursor ( ) . ch ) ;
} , { value : '01x3xx678x' } ) ;
testVim ( 't,' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 6 ) ;
helpers . doKeys ( 't' , 'x' ) ;
helpers . doKeys ( ',' ) ;
helpers . doKeys ( '2' , ',' ) ;
eq ( 3 , cm . getCursor ( ) . ch ) ;
} , { value : '01x3xx678x' } ) ;
testVim ( 'T,' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 4 ) ;
helpers . doKeys ( 'T' , 'x' ) ;
helpers . doKeys ( ',' ) ;
helpers . doKeys ( '2' , ',' ) ;
eq ( 8 , cm . getCursor ( ) . ch ) ;
} , { value : '01x3xx67xx' } ) ;
testVim ( 'fd,;' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'f' , '4' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'd' , ';' ) ;
eq ( '56789' , cm . getValue ( ) ) ;
helpers . doKeys ( 'u' ) ;
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( 'd' , ',' ) ;
eq ( '01239' , cm . getValue ( ) ) ;
} , { value : '0123456789' } ) ;
testVim ( 'Fd,;' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( 'F' , '4' ) ;
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( 'd' , ';' ) ;
eq ( '01239' , cm . getValue ( ) ) ;
helpers . doKeys ( 'u' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'd' , ',' ) ;
eq ( '56789' , cm . getValue ( ) ) ;
} , { value : '0123456789' } ) ;
testVim ( 'td,;' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 't' , '4' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'd' , ';' ) ;
eq ( '456789' , cm . getValue ( ) ) ;
helpers . doKeys ( 'u' ) ;
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( 'd' , ',' ) ;
eq ( '012349' , cm . getValue ( ) ) ;
} , { value : '0123456789' } ) ;
testVim ( 'Td,;' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( 'T' , '4' ) ;
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( 'd' , ';' ) ;
eq ( '012349' , cm . getValue ( ) ) ;
helpers . doKeys ( 'u' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'd' , ',' ) ;
eq ( '456789' , cm . getValue ( ) ) ;
} , { value : '0123456789' } ) ;
testVim ( 'fc,;' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'f' , '4' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'c' , ';' , '<Esc>' ) ;
eq ( '56789' , cm . getValue ( ) ) ;
helpers . doKeys ( 'u' ) ;
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( 'c' , ',' ) ;
eq ( '01239' , cm . getValue ( ) ) ;
} , { value : '0123456789' } ) ;
testVim ( 'Fc,;' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( 'F' , '4' ) ;
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( 'c' , ';' , '<Esc>' ) ;
eq ( '01239' , cm . getValue ( ) ) ;
helpers . doKeys ( 'u' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'c' , ',' ) ;
eq ( '56789' , cm . getValue ( ) ) ;
} , { value : '0123456789' } ) ;
testVim ( 'tc,;' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 't' , '4' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'c' , ';' , '<Esc>' ) ;
eq ( '456789' , cm . getValue ( ) ) ;
helpers . doKeys ( 'u' ) ;
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( 'c' , ',' ) ;
eq ( '012349' , cm . getValue ( ) ) ;
} , { value : '0123456789' } ) ;
testVim ( 'Tc,;' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( 'T' , '4' ) ;
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( 'c' , ';' , '<Esc>' ) ;
eq ( '012349' , cm . getValue ( ) ) ;
helpers . doKeys ( 'u' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'c' , ',' ) ;
eq ( '456789' , cm . getValue ( ) ) ;
} , { value : '0123456789' } ) ;
testVim ( 'fy,;' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'f' , '4' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'y' , ';' , 'P' ) ;
eq ( '012340123456789' , cm . getValue ( ) ) ;
helpers . doKeys ( 'u' ) ;
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( 'y' , ',' , 'P' ) ;
eq ( '012345678456789' , cm . getValue ( ) ) ;
} , { value : '0123456789' } ) ;
testVim ( 'Fy,;' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( 'F' , '4' ) ;
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( 'y' , ';' , 'p' ) ;
eq ( '012345678945678' , cm . getValue ( ) ) ;
helpers . doKeys ( 'u' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'y' , ',' , 'P' ) ;
eq ( '012340123456789' , cm . getValue ( ) ) ;
} , { value : '0123456789' } ) ;
testVim ( 'ty,;' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 't' , '4' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'y' , ';' , 'P' ) ;
eq ( '01230123456789' , cm . getValue ( ) ) ;
helpers . doKeys ( 'u' ) ;
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( 'y' , ',' , 'p' ) ;
eq ( '01234567895678' , cm . getValue ( ) ) ;
} , { value : '0123456789' } ) ;
testVim ( 'Ty,;' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( 'T' , '4' ) ;
cm . setCursor ( 0 , 9 ) ;
helpers . doKeys ( 'y' , ';' , 'p' ) ;
eq ( '01234567895678' , cm . getValue ( ) ) ;
helpers . doKeys ( 'u' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'y' , ',' , 'P' ) ;
eq ( '01230123456789' , cm . getValue ( ) ) ;
} , { value : '0123456789' } ) ;
testVim ( 'HML' , function ( cm , vim , helpers ) {
var lines = 35 ;
var textHeight = cm . defaultTextHeight ( ) ;
cm . setSize ( 600 , lines * textHeight ) ;
cm . setCursor ( 120 , 0 ) ;
helpers . doKeys ( 'H' ) ;
helpers . assertCursorAt ( 86 , 2 ) ;
helpers . doKeys ( 'L' ) ;
helpers . assertCursorAt ( 120 , 4 ) ;
helpers . doKeys ( 'M' ) ;
helpers . assertCursorAt ( 103 , 4 ) ;
} , { value : ( function ( ) {
var lines = new Array ( 100 ) ;
var upper = ' xx\n' ;
var lower = ' xx\n' ;
upper = lines . join ( upper ) ;
lower = lines . join ( lower ) ;
return upper + lower ;
} ) ( ) } ) ;
var zVals = [ ] ;
forEach ( [ 'zb' , 'zz' , 'zt' , 'z-' , 'z.' , 'z<CR>' ] , function ( e , idx ) {
var lineNum = 250 ;
var lines = 35 ;
testVim ( e , function ( cm , vim , helpers ) {
var k1 = e [ 0 ] ;
var k2 = e . substring ( 1 ) ;
var textHeight = cm . defaultTextHeight ( ) ;
cm . setSize ( 600 , lines * textHeight ) ;
cm . setCursor ( lineNum , 0 ) ;
helpers . doKeys ( k1 , k2 ) ;
zVals [ idx ] = cm . getScrollInfo ( ) . top ;
} , { value : ( function ( ) {
return new Array ( 500 ) . join ( '\n' ) ;
} ) ( ) } ) ;
} ) ;
testVim ( 'zb_to_bottom' , function ( cm , vim , helpers ) {
var lineNum = 250 ;
cm . setSize ( 600 , 35 * cm . defaultTextHeight ( ) ) ;
cm . setCursor ( lineNum , 0 ) ;
helpers . doKeys ( 'z' , 'b' ) ;
var scrollInfo = cm . getScrollInfo ( ) ;
eq ( scrollInfo . top + scrollInfo . clientHeight , cm . charCoords ( Pos ( lineNum , 0 ) , 'local' ) . bottom ) ;
} , { value : ( function ( ) {
return new Array ( 500 ) . join ( '\n' ) ;
} ) ( ) } ) ;
testVim ( 'zt_to_top' , function ( cm , vim , helpers ) {
var lineNum = 250 ;
cm . setSize ( 600 , 35 * cm . defaultTextHeight ( ) ) ;
cm . setCursor ( lineNum , 0 ) ;
helpers . doKeys ( 'z' , 't' ) ;
eq ( cm . getScrollInfo ( ) . top , cm . charCoords ( Pos ( lineNum , 0 ) , 'local' ) . top ) ;
} , { value : ( function ( ) {
return new Array ( 500 ) . join ( '\n' ) ;
} ) ( ) } ) ;
testVim ( 'zb<zz' , function ( cm , vim , helpers ) {
eq ( zVals [ 0 ] < zVals [ 1 ] , true ) ;
} ) ;
testVim ( 'zz<zt' , function ( cm , vim , helpers ) {
eq ( zVals [ 1 ] < zVals [ 2 ] , true ) ;
} ) ;
testVim ( 'zb==z-' , function ( cm , vim , helpers ) {
eq ( zVals [ 0 ] , zVals [ 3 ] ) ;
} ) ;
testVim ( 'zz==z.' , function ( cm , vim , helpers ) {
eq ( zVals [ 1 ] , zVals [ 4 ] ) ;
} ) ;
testVim ( 'zt==z<CR>' , function ( cm , vim , helpers ) {
eq ( zVals [ 2 ] , zVals [ 5 ] ) ;
} ) ;
var moveTillCharacterSandbox =
'The quick brown fox \n' ;
testVim ( 'moveTillCharacter' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
// Search for the 'q'.
cm . openDialog = helpers . fakeOpenDialog ( 'q' ) ;
helpers . doKeys ( '/' ) ;
eq ( 4 , cm . getCursor ( ) . ch ) ;
// Jump to just before the first o in the list.
helpers . doKeys ( 't' ) ;
helpers . doKeys ( 'o' ) ;
eq ( 'The quick brown fox \n' , cm . getValue ( ) ) ;
// Delete that one character.
helpers . doKeys ( 'd' ) ;
helpers . doKeys ( 't' ) ;
helpers . doKeys ( 'o' ) ;
eq ( 'The quick bown fox \n' , cm . getValue ( ) ) ;
// Delete everything until the next 'o'.
helpers . doKeys ( '.' ) ;
eq ( 'The quick box \n' , cm . getValue ( ) ) ;
// An unmatched character should have no effect.
helpers . doKeys ( 'd' ) ;
helpers . doKeys ( 't' ) ;
helpers . doKeys ( 'q' ) ;
eq ( 'The quick box \n' , cm . getValue ( ) ) ;
// Matches should only be possible on single lines.
helpers . doKeys ( 'd' ) ;
helpers . doKeys ( 't' ) ;
helpers . doKeys ( 'z' ) ;
eq ( 'The quick box \n' , cm . getValue ( ) ) ;
// After all that, the search for 'q' should still be active, so the 'N' command
// can run it again in reverse. Use that to delete everything back to the 'q'.
helpers . doKeys ( 'd' ) ;
helpers . doKeys ( 'N' ) ;
eq ( 'The ox \n' , cm . getValue ( ) ) ;
eq ( 4 , cm . getCursor ( ) . ch ) ;
} , { value : moveTillCharacterSandbox } ) ;
testVim ( 'searchForPipe' , function ( cm , vim , helpers ) {
CodeMirror . Vim . setOption ( 'pcre' , false ) ;
cm . setCursor ( 0 , 0 ) ;
// Search for the '|'.
cm . openDialog = helpers . fakeOpenDialog ( '|' ) ;
helpers . doKeys ( '/' ) ;
eq ( 4 , cm . getCursor ( ) . ch ) ;
} , { value : 'this|that' } ) ;
var scrollMotionSandbox =
'\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n' ;
testVim ( 'scrollMotion' , function ( cm , vim , helpers ) {
var prevCursor , prevScrollInfo ;
cm . setCursor ( 0 , 0 ) ;
// ctrl-y at the top of the file should have no effect.
helpers . doKeys ( '<C-y>' ) ;
eq ( 0 , cm . getCursor ( ) . line ) ;
prevScrollInfo = cm . getScrollInfo ( ) ;
helpers . doKeys ( '<C-e>' ) ;
eq ( 1 , cm . getCursor ( ) . line ) ;
is ( prevScrollInfo . top < cm . getScrollInfo ( ) . top ) ;
// Jump to the end of the sandbox.
cm . setCursor ( 1000 , 0 ) ;
prevCursor = cm . getCursor ( ) ;
// ctrl-e at the bottom of the file should have no effect.
helpers . doKeys ( '<C-e>' ) ;
eq ( prevCursor . line , cm . getCursor ( ) . line ) ;
prevScrollInfo = cm . getScrollInfo ( ) ;
helpers . doKeys ( '<C-y>' ) ;
eq ( prevCursor . line - 1 , cm . getCursor ( ) . line , "Y" ) ;
is ( prevScrollInfo . top > cm . getScrollInfo ( ) . top ) ;
} , { value : scrollMotionSandbox } ) ;
var squareBracketMotionSandbox = '' +
'({\n' + //0
' ({\n' + //11
' /*comment {\n' + //2
' */(\n' + //3
'#else \n' + //4
' /* )\n' + //5
'#if }\n' + //6
' )}*/\n' + //7
')}\n' + //8
'{}\n' + //9
'#else {{\n' + //10
'{}\n' + //11
'}\n' + //12
'{\n' + //13
'#endif\n' + //14
'}\n' + //15
'}\n' + //16
'#else' ; //17
testVim ( '[[, ]]' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( ']' , ']' ) ;
helpers . assertCursorAt ( 9 , 0 ) ;
helpers . doKeys ( '2' , ']' , ']' ) ;
helpers . assertCursorAt ( 13 , 0 ) ;
helpers . doKeys ( ']' , ']' ) ;
helpers . assertCursorAt ( 17 , 0 ) ;
helpers . doKeys ( '[' , '[' ) ;
helpers . assertCursorAt ( 13 , 0 ) ;
helpers . doKeys ( '2' , '[' , '[' ) ;
helpers . assertCursorAt ( 9 , 0 ) ;
helpers . doKeys ( '[' , '[' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
} , { value : squareBracketMotionSandbox } ) ;
testVim ( '[], ][' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( ']' , '[' ) ;
helpers . assertCursorAt ( 12 , 0 ) ;
helpers . doKeys ( '2' , ']' , '[' ) ;
helpers . assertCursorAt ( 16 , 0 ) ;
helpers . doKeys ( ']' , '[' ) ;
helpers . assertCursorAt ( 17 , 0 ) ;
helpers . doKeys ( '[' , ']' ) ;
helpers . assertCursorAt ( 16 , 0 ) ;
helpers . doKeys ( '2' , '[' , ']' ) ;
helpers . assertCursorAt ( 12 , 0 ) ;
helpers . doKeys ( '[' , ']' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
} , { value : squareBracketMotionSandbox } ) ;
testVim ( '[{, ]}' , function ( cm , vim , helpers ) {
cm . setCursor ( 4 , 10 ) ;
helpers . doKeys ( '[' , '{' ) ;
helpers . assertCursorAt ( 2 , 12 ) ;
helpers . doKeys ( '2' , '[' , '{' ) ;
helpers . assertCursorAt ( 0 , 1 ) ;
cm . setCursor ( 4 , 10 ) ;
helpers . doKeys ( ']' , '}' ) ;
helpers . assertCursorAt ( 6 , 11 ) ;
helpers . doKeys ( '2' , ']' , '}' ) ;
helpers . assertCursorAt ( 8 , 1 ) ;
cm . setCursor ( 0 , 1 ) ;
helpers . doKeys ( ']' , '}' ) ;
helpers . assertCursorAt ( 8 , 1 ) ;
helpers . doKeys ( '[' , '{' ) ;
helpers . assertCursorAt ( 0 , 1 ) ;
} , { value : squareBracketMotionSandbox } ) ;
testVim ( '[(, ])' , function ( cm , vim , helpers ) {
cm . setCursor ( 4 , 10 ) ;
helpers . doKeys ( '[' , '(' ) ;
helpers . assertCursorAt ( 3 , 14 ) ;
helpers . doKeys ( '2' , '[' , '(' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
cm . setCursor ( 4 , 10 ) ;
helpers . doKeys ( ']' , ')' ) ;
helpers . assertCursorAt ( 5 , 11 ) ;
helpers . doKeys ( '2' , ']' , ')' ) ;
helpers . assertCursorAt ( 8 , 0 ) ;
helpers . doKeys ( '[' , '(' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
helpers . doKeys ( ']' , ')' ) ;
helpers . assertCursorAt ( 8 , 0 ) ;
} , { value : squareBracketMotionSandbox } ) ;
testVim ( '[*, ]*, [/, ]/' , function ( cm , vim , helpers ) {
forEach ( [ '*' , '/' ] , function ( key ) {
cm . setCursor ( 7 , 0 ) ;
helpers . doKeys ( '2' , '[' , key ) ;
helpers . assertCursorAt ( 2 , 2 ) ;
helpers . doKeys ( '2' , ']' , key ) ;
helpers . assertCursorAt ( 7 , 5 ) ;
} ) ;
} , { value : squareBracketMotionSandbox } ) ;
testVim ( '[#, ]#' , function ( cm , vim , helpers ) {
cm . setCursor ( 10 , 3 ) ;
helpers . doKeys ( '2' , '[' , '#' ) ;
helpers . assertCursorAt ( 4 , 0 ) ;
helpers . doKeys ( '5' , ']' , '#' ) ;
helpers . assertCursorAt ( 17 , 0 ) ;
cm . setCursor ( 10 , 3 ) ;
helpers . doKeys ( ']' , '#' ) ;
helpers . assertCursorAt ( 14 , 0 ) ;
} , { value : squareBracketMotionSandbox } ) ;
testVim ( '[m, ]m, [M, ]M' , function ( cm , vim , helpers ) {
cm . setCursor ( 11 , 0 ) ;
helpers . doKeys ( '[' , 'm' ) ;
helpers . assertCursorAt ( 10 , 7 ) ;
helpers . doKeys ( '4' , '[' , 'm' ) ;
helpers . assertCursorAt ( 1 , 3 ) ;
helpers . doKeys ( '5' , ']' , 'm' ) ;
helpers . assertCursorAt ( 11 , 0 ) ;
helpers . doKeys ( '[' , 'M' ) ;
helpers . assertCursorAt ( 9 , 1 ) ;
helpers . doKeys ( '3' , ']' , 'M' ) ;
helpers . assertCursorAt ( 15 , 0 ) ;
helpers . doKeys ( '5' , '[' , 'M' ) ;
helpers . assertCursorAt ( 7 , 3 ) ;
} , { value : squareBracketMotionSandbox } ) ;
testVim ( 'i_indent_right' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 3 ) ;
var expectedValue = ' word1\nword2\nword3 ' ;
helpers . doKeys ( 'i' , '<C-t>' ) ;
eq ( expectedValue , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 5 ) ;
} , { value : ' word1\nword2\nword3 ' , indentUnit : 2 } ) ;
testVim ( 'i_indent_left' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 3 ) ;
var expectedValue = ' word1\nword2\nword3 ' ;
helpers . doKeys ( 'i' , '<C-d>' ) ;
eq ( expectedValue , cm . getValue ( ) ) ;
helpers . assertCursorAt ( 0 , 1 ) ;
} , { value : ' word1\nword2\nword3 ' , indentUnit : 2 } ) ;
// Ex mode tests
testVim ( 'ex_go_to_line' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doEx ( '4' ) ;
helpers . assertCursorAt ( 3 , 0 ) ;
} , { value : 'a\nb\nc\nd\ne\n' } ) ;
testVim ( 'ex_go_to_mark' , function ( cm , vim , helpers ) {
cm . setCursor ( 3 , 0 ) ;
helpers . doKeys ( 'm' , 'a' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doEx ( '\'a' ) ;
helpers . assertCursorAt ( 3 , 0 ) ;
} , { value : 'a\nb\nc\nd\ne\n' } ) ;
testVim ( 'ex_go_to_line_offset' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doEx ( '+3' ) ;
helpers . assertCursorAt ( 3 , 0 ) ;
helpers . doEx ( '-1' ) ;
helpers . assertCursorAt ( 2 , 0 ) ;
helpers . doEx ( '.2' ) ;
helpers . assertCursorAt ( 4 , 0 ) ;
helpers . doEx ( '.-3' ) ;
helpers . assertCursorAt ( 1 , 0 ) ;
} , { value : 'a\nb\nc\nd\ne\n' } ) ;
testVim ( 'ex_go_to_mark_offset' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 0 ) ;
helpers . doKeys ( 'm' , 'a' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doEx ( '\'a1' ) ;
helpers . assertCursorAt ( 3 , 0 ) ;
helpers . doEx ( '\'a-1' ) ;
helpers . assertCursorAt ( 1 , 0 ) ;
helpers . doEx ( '\'a+2' ) ;
helpers . assertCursorAt ( 4 , 0 ) ;
} , { value : 'a\nb\nc\nd\ne\n' } ) ;
testVim ( 'ex_write' , function ( cm , vim , helpers ) {
var tmp = CodeMirror . commands . save ;
var written ;
var actualCm ;
CodeMirror . commands . save = function ( cm ) {
written = true ;
actualCm = cm ;
} ;
// Test that w, wr, wri ... write all trigger :write.
var command = 'write' ;
for ( var i = 1 ; i < command . length ; i ++ ) {
written = false ;
actualCm = null ;
helpers . doEx ( command . substring ( 0 , i ) ) ;
eq ( written , true ) ;
eq ( actualCm , cm ) ;
}
CodeMirror . commands . save = tmp ;
} ) ;
testVim ( 'ex_sort' , function ( cm , vim , helpers ) {
helpers . doEx ( 'sort' ) ;
eq ( 'Z\na\nb\nc\nd' , cm . getValue ( ) ) ;
} , { value : 'b\nZ\nd\nc\na' } ) ;
testVim ( 'ex_sort_reverse' , function ( cm , vim , helpers ) {
helpers . doEx ( 'sort!' ) ;
eq ( 'd\nc\nb\na' , cm . getValue ( ) ) ;
} , { value : 'b\nd\nc\na' } ) ;
testVim ( 'ex_sort_range' , function ( cm , vim , helpers ) {
helpers . doEx ( '2,3sort' ) ;
eq ( 'b\nc\nd\na' , cm . getValue ( ) ) ;
} , { value : 'b\nd\nc\na' } ) ;
testVim ( 'ex_sort_oneline' , function ( cm , vim , helpers ) {
helpers . doEx ( '2sort' ) ;
// Expect no change.
eq ( 'b\nd\nc\na' , cm . getValue ( ) ) ;
} , { value : 'b\nd\nc\na' } ) ;
testVim ( 'ex_sort_ignoreCase' , function ( cm , vim , helpers ) {
helpers . doEx ( 'sort i' ) ;
eq ( 'a\nb\nc\nd\nZ' , cm . getValue ( ) ) ;
} , { value : 'b\nZ\nd\nc\na' } ) ;
testVim ( 'ex_sort_unique' , function ( cm , vim , helpers ) {
helpers . doEx ( 'sort u' ) ;
eq ( 'Z\na\nb\nc\nd' , cm . getValue ( ) ) ;
} , { value : 'b\nZ\na\na\nd\na\nc\na' } ) ;
testVim ( 'ex_sort_decimal' , function ( cm , vim , helpers ) {
helpers . doEx ( 'sort d' ) ;
eq ( 'd3\n s5\n6\n.9' , cm . getValue ( ) ) ;
} , { value : '6\nd3\n s5\n.9' } ) ;
testVim ( 'ex_sort_decimal_negative' , function ( cm , vim , helpers ) {
helpers . doEx ( 'sort d' ) ;
eq ( 'z-9\nd3\n s5\n6\n.9' , cm . getValue ( ) ) ;
} , { value : '6\nd3\n s5\n.9\nz-9' } ) ;
testVim ( 'ex_sort_decimal_reverse' , function ( cm , vim , helpers ) {
helpers . doEx ( 'sort! d' ) ;
eq ( '.9\n6\n s5\nd3' , cm . getValue ( ) ) ;
} , { value : '6\nd3\n s5\n.9' } ) ;
testVim ( 'ex_sort_hex' , function ( cm , vim , helpers ) {
helpers . doEx ( 'sort x' ) ;
eq ( ' s5\n6\n.9\n&0xB\nd3' , cm . getValue ( ) ) ;
} , { value : '6\nd3\n s5\n&0xB\n.9' } ) ;
testVim ( 'ex_sort_octal' , function ( cm , vim , helpers ) {
helpers . doEx ( 'sort o' ) ;
eq ( '.9\n.8\nd3\n s5\n6' , cm . getValue ( ) ) ;
} , { value : '6\nd3\n s5\n.9\n.8' } ) ;
testVim ( 'ex_sort_decimal_mixed' , function ( cm , vim , helpers ) {
helpers . doEx ( 'sort d' ) ;
eq ( 'z\ny\nc1\nb2\na3' , cm . getValue ( ) ) ;
} , { value : 'a3\nz\nc1\ny\nb2' } ) ;
testVim ( 'ex_sort_decimal_mixed_reverse' , function ( cm , vim , helpers ) {
helpers . doEx ( 'sort! d' ) ;
eq ( 'a3\nb2\nc1\nz\ny' , cm . getValue ( ) ) ;
} , { value : 'a3\nz\nc1\ny\nb2' } ) ;
testVim ( 'ex_sort_pattern_alpha' , function ( cm , vim , helpers ) {
helpers . doEx ( 'sort /[a-z]/' ) ;
eq ( 'a3\nb2\nc1\ny\nz' , cm . getValue ( ) ) ;
} , { value : 'z\ny\nc1\nb2\na3' } ) ;
testVim ( 'ex_sort_pattern_alpha_reverse' , function ( cm , vim , helpers ) {
helpers . doEx ( 'sort! /[a-z]/' ) ;
eq ( 'z\ny\nc1\nb2\na3' , cm . getValue ( ) ) ;
} , { value : 'z\ny\nc1\nb2\na3' } ) ;
testVim ( 'ex_sort_pattern_alpha_ignoreCase' , function ( cm , vim , helpers ) {
helpers . doEx ( 'sort i/[a-z]/' ) ;
eq ( 'a3\nb2\nC1\nY\nz' , cm . getValue ( ) ) ;
} , { value : 'z\nY\nC1\nb2\na3' } ) ;
testVim ( 'ex_sort_pattern_alpha_longer' , function ( cm , vim , helpers ) {
helpers . doEx ( 'sort /[a-z]+/' ) ;
eq ( 'a\naa\nab\nade\nadele\nadelle\nadriana\nalex\nalexandra\nb\nc\ny\nz' , cm . getValue ( ) ) ;
} , { value : 'z\nab\naa\nade\nadelle\nalexandra\nalex\nadriana\nadele\ny\nc\nb\na' } ) ;
testVim ( 'ex_sort_pattern_alpha_only' , function ( cm , vim , helpers ) {
helpers . doEx ( 'sort /^[a-z]$/' ) ;
eq ( 'z1\ny2\na3\nb\nc' , cm . getValue ( ) ) ;
} , { value : 'z1\ny2\na3\nc\nb' } ) ;
testVim ( 'ex_sort_pattern_alpha_only_reverse' , function ( cm , vim , helpers ) {
helpers . doEx ( 'sort! /^[a-z]$/' ) ;
eq ( 'c\nb\nz1\ny2\na3' , cm . getValue ( ) ) ;
} , { value : 'z1\ny2\na3\nc\nb' } ) ;
testVim ( 'ex_sort_pattern_alpha_num' , function ( cm , vim , helpers ) {
helpers . doEx ( 'sort /[a-z][0-9]/' ) ;
eq ( 'c\nb\na3\ny2\nz1' , cm . getValue ( ) ) ;
} , { value : 'z1\ny2\na3\nc\nb' } ) ;
// test for :global command
testVim ( 'ex_global' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doEx ( 'g/one/s//two' ) ;
eq ( 'two two\n two two\n two two' , cm . getValue ( ) ) ;
helpers . doEx ( '1,2g/two/s//one' ) ;
eq ( 'one one\n one one\n two two' , cm . getValue ( ) ) ;
} , { value : 'one one\n one one\n one one' } ) ;
testVim ( 'ex_global_confirm' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
var onKeyDown ;
var openDialogSave = cm . openDialog ;
var KEYCODES = {
a : 65 ,
n : 78 ,
q : 81 ,
y : 89
} ;
// Intercept the ex command, 'global'
cm . openDialog = function ( template , callback , options ) {
// Intercept the prompt for the embedded ex command, 'substitute'
cm . openDialog = function ( template , callback , options ) {
onKeyDown = options . onKeyDown ;
} ;
callback ( 'g/one/s//two/gc' ) ;
} ;
helpers . doKeys ( ':' ) ;
var close = function ( ) { } ;
onKeyDown ( { keyCode : KEYCODES . n } , '' , close ) ;
onKeyDown ( { keyCode : KEYCODES . y } , '' , close ) ;
onKeyDown ( { keyCode : KEYCODES . a } , '' , close ) ;
onKeyDown ( { keyCode : KEYCODES . q } , '' , close ) ;
onKeyDown ( { keyCode : KEYCODES . y } , '' , close ) ;
eq ( 'one two\n two two\n one one\n two one\n one one' , cm . getValue ( ) ) ;
} , { value : 'one one\n one one\n one one\n one one\n one one' } ) ;
// Basic substitute tests.
testVim ( 'ex_substitute_same_line' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 0 ) ;
helpers . doEx ( 's/one/two/g' ) ;
eq ( 'one one\n two two' , cm . getValue ( ) ) ;
} , { value : 'one one\n one one' } ) ;
testVim ( 'ex_substitute_alternate_separator' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 0 ) ;
helpers . doEx ( 's#o/e#two#g' ) ;
eq ( 'o/e o/e\n two two' , cm . getValue ( ) ) ;
} , { value : 'o/e o/e\n o/e o/e' } ) ;
testVim ( 'ex_substitute_full_file' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 0 ) ;
helpers . doEx ( '%s/one/two/g' ) ;
eq ( 'two two\n two two' , cm . getValue ( ) ) ;
} , { value : 'one one\n one one' } ) ;
testVim ( 'ex_substitute_input_range' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 0 ) ;
helpers . doEx ( '1,3s/\\d/0/g' ) ;
eq ( '0\n0\n0\n4' , cm . getValue ( ) ) ;
} , { value : '1\n2\n3\n4' } ) ;
testVim ( 'ex_substitute_range_current_to_input' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 0 ) ;
helpers . doEx ( '.,3s/\\d/0/g' ) ;
eq ( '1\n0\n0\n4' , cm . getValue ( ) ) ;
} , { value : '1\n2\n3\n4' } ) ;
testVim ( 'ex_substitute_range_input_to_current' , function ( cm , vim , helpers ) {
cm . setCursor ( 3 , 0 ) ;
helpers . doEx ( '2,.s/\\d/0/g' ) ;
eq ( '1\n0\n0\n0\n5' , cm . getValue ( ) ) ;
} , { value : '1\n2\n3\n4\n5' } ) ;
testVim ( 'ex_substitute_range_offset' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 0 ) ;
helpers . doEx ( '-1,+1s/\\d/0/g' ) ;
eq ( '1\n0\n0\n0\n5' , cm . getValue ( ) ) ;
} , { value : '1\n2\n3\n4\n5' } ) ;
testVim ( 'ex_substitute_range_implicit_offset' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doEx ( '.1,.3s/\\d/0/g' ) ;
eq ( '1\n0\n0\n0\n5' , cm . getValue ( ) ) ;
} , { value : '1\n2\n3\n4\n5' } ) ;
testVim ( 'ex_substitute_to_eof' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 0 ) ;
helpers . doEx ( '.,$s/\\d/0/g' ) ;
eq ( '1\n2\n0\n0\n0' , cm . getValue ( ) ) ;
} , { value : '1\n2\n3\n4\n5' } ) ;
testVim ( 'ex_substitute_to_relative_eof' , function ( cm , vim , helpers ) {
cm . setCursor ( 4 , 0 ) ;
helpers . doEx ( '2,$-2s/\\d/0/g' ) ;
eq ( '1\n0\n0\n4\n5' , cm . getValue ( ) ) ;
} , { value : '1\n2\n3\n4\n5' } ) ;
testVim ( 'ex_substitute_range_mark' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 0 ) ;
helpers . doKeys ( 'ma' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doEx ( '.,\'as/\\d/0/g' ) ;
eq ( '0\n0\n0\n4\n5' , cm . getValue ( ) ) ;
} , { value : '1\n2\n3\n4\n5' } ) ;
testVim ( 'ex_substitute_range_mark_offset' , function ( cm , vim , helpers ) {
cm . setCursor ( 2 , 0 ) ;
helpers . doKeys ( 'ma' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doEx ( '\'a-1,\'a+1s/\\d/0/g' ) ;
eq ( '1\n0\n0\n0\n5' , cm . getValue ( ) ) ;
} , { value : '1\n2\n3\n4\n5' } ) ;
testVim ( 'ex_substitute_visual_range' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 0 ) ;
// Set last visual mode selection marks '< and '> at lines 2 and 4
helpers . doKeys ( 'V' , '2' , 'j' , 'v' ) ;
helpers . doEx ( '\'<,\'>s/\\d/0/g' ) ;
eq ( '1\n0\n0\n0\n5' , cm . getValue ( ) ) ;
} , { value : '1\n2\n3\n4\n5' } ) ;
testVim ( 'ex_substitute_empty_query' , function ( cm , vim , helpers ) {
// If the query is empty, use last query.
cm . setCursor ( 1 , 0 ) ;
cm . openDialog = helpers . fakeOpenDialog ( '1' ) ;
helpers . doKeys ( '/' ) ;
helpers . doEx ( 's//b/g' ) ;
eq ( 'abb ab2 ab3' , cm . getValue ( ) ) ;
} , { value : 'a11 a12 a13' } ) ;
testVim ( 'ex_substitute_javascript' , function ( cm , vim , helpers ) {
CodeMirror . Vim . setOption ( 'pcre' , false ) ;
cm . setCursor ( 1 , 0 ) ;
// Throw all the things that javascript likes to treat as special values
// into the replace part. All should be literal (this is VIM).
helpers . doEx ( 's/\\(\\d+\\)/$$ $\' $` $& \\1/g' )
eq ( 'a $$ $\' $` $& 0 b' , cm . getValue ( ) ) ;
} , { value : 'a 0 b' } ) ;
testVim ( 'ex_substitute_empty_arguments' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
helpers . doEx ( 's/a/b/g' ) ;
cm . setCursor ( 1 , 0 ) ;
helpers . doEx ( 's' ) ;
eq ( 'b b\nb a' , cm . getValue ( ) ) ;
} , { value : 'a a\na a' } ) ;
// More complex substitute tests that test both pcre and nopcre options.
function testSubstitute ( name , options ) {
testVim ( name + '_pcre' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 0 ) ;
CodeMirror . Vim . setOption ( 'pcre' , true ) ;
helpers . doEx ( options . expr ) ;
eq ( options . expectedValue , cm . getValue ( ) ) ;
} , options ) ;
// If no noPcreExpr is defined, assume that it's the same as the expr.
var noPcreExpr = options . noPcreExpr ? options . noPcreExpr : options . expr ;
testVim ( name + '_nopcre' , function ( cm , vim , helpers ) {
cm . setCursor ( 1 , 0 ) ;
CodeMirror . Vim . setOption ( 'pcre' , false ) ;
helpers . doEx ( noPcreExpr ) ;
eq ( options . expectedValue , cm . getValue ( ) ) ;
} , options ) ;
}
testSubstitute ( 'ex_substitute_capture' , {
value : 'a11 a12 a13' ,
expectedValue : 'a1111 a1212 a1313' ,
// $n is a backreference
expr : 's/(\\d+)/$1$1/g' ,
// \n is a backreference.
noPcreExpr : 's/\\(\\d+\\)/\\1\\1/g' } ) ;
testSubstitute ( 'ex_substitute_capture2' , {
value : 'a 0 b' ,
expectedValue : 'a $00 b' ,
expr : 's/(\\d+)/$$$1$1/g' ,
noPcreExpr : 's/\\(\\d+\\)/$\\1\\1/g' } ) ;
testSubstitute ( 'ex_substitute_nocapture' , {
value : 'a11 a12 a13' ,
expectedValue : 'a$1$1 a$1$1 a$1$1' ,
expr : 's/(\\d+)/$$1$$1/g' ,
noPcreExpr : 's/\\(\\d+\\)/$1$1/g' } ) ;
testSubstitute ( 'ex_substitute_nocapture2' , {
value : 'a 0 b' ,
expectedValue : 'a $10 b' ,
expr : 's/(\\d+)/$$1$1/g' ,
noPcreExpr : 's/\\(\\d+\\)/\\$1\\1/g' } ) ;
testSubstitute ( 'ex_substitute_nocapture' , {
value : 'a b c' ,
expectedValue : 'a $ c' ,
expr : 's/b/$$/' ,
noPcreExpr : 's/b/$/' } ) ;
testSubstitute ( 'ex_substitute_slash_regex' , {
value : 'one/two \n three/four' ,
expectedValue : 'one|two \n three|four' ,
expr : '%s/\\//|' } ) ;
testSubstitute ( 'ex_substitute_pipe_regex' , {
value : 'one|two \n three|four' ,
expectedValue : 'one,two \n three,four' ,
expr : '%s/\\|/,/' ,
noPcreExpr : '%s/|/,/' } ) ;
testSubstitute ( 'ex_substitute_or_regex' , {
value : 'one|two \n three|four' ,
expectedValue : 'ana|twa \n thraa|faar' ,
expr : '%s/o|e|u/a/g' ,
noPcreExpr : '%s/o\\|e\\|u/a/g' } ) ;
testSubstitute ( 'ex_substitute_or_word_regex' , {
value : 'one|two \n three|four' ,
expectedValue : 'five|five \n three|four' ,
expr : '%s/(one|two)/five/g' ,
noPcreExpr : '%s/\\(one\\|two\\)/five/g' } ) ;
testSubstitute ( 'ex_substitute_forward_slash_regex' , {
value : 'forward slash \/ was here' ,
expectedValue : 'forward slash was here' ,
expr : '%s#\\/##g' ,
noPcreExpr : '%s#/##g' } ) ;
testVim ( "ex_substitute_ampersand_pcre" , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
CodeMirror . Vim . setOption ( 'pcre' , true ) ;
helpers . doEx ( '%s/foo/namespace.&/' ) ;
eq ( "namespace.foo" , cm . getValue ( ) ) ;
} , { value : 'foo' } ) ;
testVim ( "ex_substitute_ampersand_multiple_pcre" , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
CodeMirror . Vim . setOption ( 'pcre' , true ) ;
helpers . doEx ( '%s/f.o/namespace.&/' ) ;
eq ( "namespace.foo\nnamespace.fzo" , cm . getValue ( ) ) ;
} , { value : 'foo\nfzo' } ) ;
testVim ( "ex_escaped_ampersand_should_not_substitute_pcre" , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 0 ) ;
CodeMirror . Vim . setOption ( 'pcre' , true ) ;
helpers . doEx ( '%s/foo/namespace.\\&/' ) ;
eq ( "namespace.&" , cm . getValue ( ) ) ;
} , { value : 'foo' } ) ;
testSubstitute ( 'ex_substitute_backslashslash_regex' , {
value : 'one\\two \n three\\four' ,
expectedValue : 'one,two \n three,four' ,
expr : '%s/\\\\/,' } ) ;
testSubstitute ( 'ex_substitute_slash_replacement' , {
value : 'one,two \n three,four' ,
expectedValue : 'one/two \n three/four' ,
expr : '%s/,/\\/' } ) ;
testSubstitute ( 'ex_substitute_backslash_replacement' , {
value : 'one,two \n three,four' ,
expectedValue : 'one\\two \n three\\four' ,
expr : '%s/,/\\\\/g' } ) ;
testSubstitute ( 'ex_substitute_multibackslash_replacement' , {
value : 'one,two \n three,four' ,
expectedValue : 'one\\\\\\\\two \n three\\\\\\\\four' , // 2*8 backslashes.
expr : '%s/,/\\\\\\\\\\\\\\\\/g' } ) ; // 16 backslashes.
testSubstitute ( 'ex_substitute_dollar_match' , {
value : 'one,two \n three,four' ,
expectedValue : 'one,two ,\n three,four' ,
expr : '%s/$/,/g' } ) ;
testSubstitute ( 'ex_substitute_newline_match' , {
value : 'one,two \n three,four' ,
expectedValue : 'one,two , three,four' ,
expr : '%s/\\n/,/g' } ) ;
testSubstitute ( 'ex_substitute_newline_replacement' , {
value : 'one,two \n three,four' ,
expectedValue : 'one\ntwo \n three\nfour' ,
expr : '%s/,/\\n/g' } ) ;
testSubstitute ( 'ex_substitute_braces_word' , {
value : 'ababab abb ab{2}' ,
expectedValue : 'ab abb ab{2}' ,
expr : '%s/(ab){2}//g' ,
noPcreExpr : '%s/\\(ab\\)\\{2\\}//g' } ) ;
testSubstitute ( 'ex_substitute_braces_range' , {
value : 'a aa aaa aaaa' ,
expectedValue : 'a a' ,
expr : '%s/a{2,3}//g' ,
noPcreExpr : '%s/a\\{2,3\\}//g' } ) ;
testSubstitute ( 'ex_substitute_braces_literal' , {
value : 'ababab abb ab{2}' ,
expectedValue : 'ababab abb ' ,
expr : '%s/ab\\{2\\}//g' ,
noPcreExpr : '%s/ab{2}//g' } ) ;
testSubstitute ( 'ex_substitute_braces_char' , {
value : 'ababab abb ab{2}' ,
expectedValue : 'ababab ab{2}' ,
expr : '%s/ab{2}//g' ,
noPcreExpr : '%s/ab\\{2\\}//g' } ) ;
testSubstitute ( 'ex_substitute_braces_no_escape' , {
value : 'ababab abb ab{2}' ,
expectedValue : 'ababab ab{2}' ,
expr : '%s/ab{2}//g' ,
noPcreExpr : '%s/ab\\{2}//g' } ) ;
testSubstitute ( 'ex_substitute_count' , {
value : '1\n2\n3\n4' ,
expectedValue : '1\n0\n0\n4' ,
expr : 's/\\d/0/i 2' } ) ;
testSubstitute ( 'ex_substitute_count_with_range' , {
value : '1\n2\n3\n4' ,
expectedValue : '1\n2\n0\n0' ,
expr : '1,3s/\\d/0/ 3' } ) ;
testSubstitute ( 'ex_substitute_not_global' , {
value : 'aaa\nbaa\ncaa' ,
expectedValue : 'xaa\nbxa\ncxa' ,
expr : '%s/a/x/' } ) ;
function testSubstituteConfirm ( name , command , initialValue , expectedValue , keys , finalPos ) {
testVim ( name , function ( cm , vim , helpers ) {
var savedOpenDialog = cm . openDialog ;
var savedKeyName = CodeMirror . keyName ;
var onKeyDown ;
var recordedCallback ;
var closed = true ; // Start out closed, set false on second openDialog.
function close ( ) {
closed = true ;
}
// First openDialog should save callback.
cm . openDialog = function ( template , callback , options ) {
recordedCallback = callback ;
}
// Do first openDialog.
helpers . doKeys ( ':' ) ;
// Second openDialog should save keyDown handler.
cm . openDialog = function ( template , callback , options ) {
onKeyDown = options . onKeyDown ;
closed = false ;
} ;
// Return the command to Vim and trigger second openDialog.
recordedCallback ( command ) ;
// The event should really use keyCode, but here just mock it out and use
// key and replace keyName to just return key.
CodeMirror . keyName = function ( e ) { return e . key ; }
keys = keys . toUpperCase ( ) ;
for ( var i = 0 ; i < keys . length ; i ++ ) {
is ( ! closed ) ;
onKeyDown ( { key : keys . charAt ( i ) } , '' , close ) ;
}
try {
eq ( expectedValue , cm . getValue ( ) ) ;
helpers . assertCursorAt ( finalPos ) ;
is ( closed ) ;
} catch ( e ) {
throw e
} finally {
// Restore overridden functions.
CodeMirror . keyName = savedKeyName ;
cm . openDialog = savedOpenDialog ;
}
} , { value : initialValue } ) ;
}
testSubstituteConfirm ( 'ex_substitute_confirm_emptydoc' ,
'%s/x/b/c' , '' , '' , '' , makeCursor ( 0 , 0 ) ) ;
testSubstituteConfirm ( 'ex_substitute_confirm_nomatch' ,
'%s/x/b/c' , 'ba a\nbab' , 'ba a\nbab' , '' , makeCursor ( 0 , 0 ) ) ;
testSubstituteConfirm ( 'ex_substitute_confirm_accept' ,
'%s/a/b/cg' , 'ba a\nbab' , 'bb b\nbbb' , 'yyy' , makeCursor ( 1 , 1 ) ) ;
testSubstituteConfirm ( 'ex_substitute_confirm_random_keys' ,
'%s/a/b/cg' , 'ba a\nbab' , 'bb b\nbbb' , 'ysdkywerty' , makeCursor ( 1 , 1 ) ) ;
testSubstituteConfirm ( 'ex_substitute_confirm_some' ,
'%s/a/b/cg' , 'ba a\nbab' , 'bb a\nbbb' , 'yny' , makeCursor ( 1 , 1 ) ) ;
testSubstituteConfirm ( 'ex_substitute_confirm_all' ,
'%s/a/b/cg' , 'ba a\nbab' , 'bb b\nbbb' , 'a' , makeCursor ( 1 , 1 ) ) ;
testSubstituteConfirm ( 'ex_substitute_confirm_accept_then_all' ,
'%s/a/b/cg' , 'ba a\nbab' , 'bb b\nbbb' , 'ya' , makeCursor ( 1 , 1 ) ) ;
testSubstituteConfirm ( 'ex_substitute_confirm_quit' ,
'%s/a/b/cg' , 'ba a\nbab' , 'bb a\nbab' , 'yq' , makeCursor ( 0 , 3 ) ) ;
testSubstituteConfirm ( 'ex_substitute_confirm_last' ,
'%s/a/b/cg' , 'ba a\nbab' , 'bb b\nbab' , 'yl' , makeCursor ( 0 , 3 ) ) ;
testSubstituteConfirm ( 'ex_substitute_confirm_oneline' ,
'1s/a/b/cg' , 'ba a\nbab' , 'bb b\nbab' , 'yl' , makeCursor ( 0 , 3 ) ) ;
testSubstituteConfirm ( 'ex_substitute_confirm_range_accept' ,
'1,2s/a/b/cg' , 'aa\na \na\na' , 'bb\nb \na\na' , 'yyy' , makeCursor ( 1 , 0 ) ) ;
testSubstituteConfirm ( 'ex_substitute_confirm_range_some' ,
'1,3s/a/b/cg' , 'aa\na \na\na' , 'ba\nb \nb\na' , 'ynyy' , makeCursor ( 2 , 0 ) ) ;
testSubstituteConfirm ( 'ex_substitute_confirm_range_all' ,
'1,3s/a/b/cg' , 'aa\na \na\na' , 'bb\nb \nb\na' , 'a' , makeCursor ( 2 , 0 ) ) ;
testSubstituteConfirm ( 'ex_substitute_confirm_range_last' ,
'1,3s/a/b/cg' , 'aa\na \na\na' , 'bb\nb \na\na' , 'yyl' , makeCursor ( 1 , 0 ) ) ;
//:noh should clear highlighting of search-results but allow to resume search through n
testVim ( 'ex_noh_clearSearchHighlight' , function ( cm , vim , helpers ) {
cm . openDialog = helpers . fakeOpenDialog ( 'match' ) ;
helpers . doKeys ( '?' ) ;
helpers . doEx ( 'noh' ) ;
eq ( vim . searchState _ . getOverlay ( ) , null , 'match-highlighting wasn\'t cleared' ) ;
helpers . doKeys ( 'n' ) ;
helpers . assertCursorAt ( 0 , 11 , 'can\'t resume search after clearing highlighting' ) ;
} , { value : 'match nope match \n nope Match' } ) ;
testVim ( 'ex_yank' , function ( cm , vim , helpers ) {
var curStart = makeCursor ( 3 , 0 ) ;
cm . setCursor ( curStart ) ;
helpers . doEx ( 'y' ) ;
var register = helpers . getRegisterController ( ) . getRegister ( ) ;
var line = cm . getLine ( 3 ) ;
eq ( line + '\n' , register . toString ( ) ) ;
} ) ;
testVim ( 'set_boolean' , function ( cm , vim , helpers ) {
CodeMirror . Vim . defineOption ( 'testoption' , true , 'boolean' ) ;
// Test default value is set.
is ( CodeMirror . Vim . getOption ( 'testoption' ) ) ;
// Test fail to set to non-boolean
var result = CodeMirror . Vim . setOption ( 'testoption' , '5' ) ;
is ( result instanceof Error ) ;
// Test setOption
CodeMirror . Vim . setOption ( 'testoption' , false ) ;
is ( ! CodeMirror . Vim . getOption ( 'testoption' ) ) ;
} ) ;
testVim ( 'ex_set_boolean' , function ( cm , vim , helpers ) {
CodeMirror . Vim . defineOption ( 'testoption' , true , 'boolean' ) ;
// Test default value is set.
is ( CodeMirror . Vim . getOption ( 'testoption' ) ) ;
is ( ! cm . state . currentNotificationClose ) ;
// Test fail to set to non-boolean
helpers . doEx ( 'set testoption=22' ) ;
is ( cm . state . currentNotificationClose ) ;
// Test setOption
helpers . doEx ( 'set notestoption' ) ;
is ( ! CodeMirror . Vim . getOption ( 'testoption' ) ) ;
} ) ;
testVim ( 'set_string' , function ( cm , vim , helpers ) {
CodeMirror . Vim . defineOption ( 'testoption' , 'a' , 'string' ) ;
// Test default value is set.
eq ( 'a' , CodeMirror . Vim . getOption ( 'testoption' ) ) ;
// Test no fail to set non-string.
var result = CodeMirror . Vim . setOption ( 'testoption' , true ) ;
is ( ! result ) ;
// Test fail to set 'notestoption'
result = CodeMirror . Vim . setOption ( 'notestoption' , 'b' ) ;
is ( result instanceof Error ) ;
// Test setOption
CodeMirror . Vim . setOption ( 'testoption' , 'c' ) ;
eq ( 'c' , CodeMirror . Vim . getOption ( 'testoption' ) ) ;
} ) ;
testVim ( 'ex_set_string' , function ( cm , vim , helpers ) {
CodeMirror . Vim . defineOption ( 'testopt' , 'a' , 'string' ) ;
// Test default value is set.
eq ( 'a' , CodeMirror . Vim . getOption ( 'testopt' ) ) ;
// Test fail to set 'notestopt'
is ( ! cm . state . currentNotificationClose ) ;
helpers . doEx ( 'set notestopt=b' ) ;
is ( cm . state . currentNotificationClose ) ;
// Test setOption
helpers . doEx ( 'set testopt=c' )
eq ( 'c' , CodeMirror . Vim . getOption ( 'testopt' ) ) ;
helpers . doEx ( 'set testopt=c' )
eq ( 'c' , CodeMirror . Vim . getOption ( 'testopt' , cm ) ) ; //local || global
eq ( 'c' , CodeMirror . Vim . getOption ( 'testopt' , cm , { scope : 'local' } ) ) ; // local
eq ( 'c' , CodeMirror . Vim . getOption ( 'testopt' , cm , { scope : 'global' } ) ) ; // global
eq ( 'c' , CodeMirror . Vim . getOption ( 'testopt' ) ) ; // global
// Test setOption global
helpers . doEx ( 'setg testopt=d' )
eq ( 'c' , CodeMirror . Vim . getOption ( 'testopt' , cm ) ) ;
eq ( 'c' , CodeMirror . Vim . getOption ( 'testopt' , cm , { scope : 'local' } ) ) ;
eq ( 'd' , CodeMirror . Vim . getOption ( 'testopt' , cm , { scope : 'global' } ) ) ;
eq ( 'd' , CodeMirror . Vim . getOption ( 'testopt' ) ) ;
// Test setOption local
helpers . doEx ( 'setl testopt=e' )
eq ( 'e' , CodeMirror . Vim . getOption ( 'testopt' , cm ) ) ;
eq ( 'e' , CodeMirror . Vim . getOption ( 'testopt' , cm , { scope : 'local' } ) ) ;
eq ( 'd' , CodeMirror . Vim . getOption ( 'testopt' , cm , { scope : 'global' } ) ) ;
eq ( 'd' , CodeMirror . Vim . getOption ( 'testopt' ) ) ;
} ) ;
testVim ( 'ex_set_callback' , function ( cm , vim , helpers ) {
var global ;
function cb ( val , cm , cfg ) {
if ( val === undefined ) {
// Getter
if ( cm ) {
return cm . _local ;
} else {
return global ;
}
} else {
// Setter
if ( cm ) {
cm . _local = val ;
} else {
global = val ;
}
}
}
CodeMirror . Vim . defineOption ( 'testopt' , 'a' , 'string' , cb ) ;
// Test default value is set.
eq ( 'a' , CodeMirror . Vim . getOption ( 'testopt' ) ) ;
// Test fail to set 'notestopt'
is ( ! cm . state . currentNotificationClose ) ;
helpers . doEx ( 'set notestopt=b' ) ;
is ( cm . state . currentNotificationClose ) ;
// Test setOption (Identical to the string tests, but via callback instead)
helpers . doEx ( 'set testopt=c' )
eq ( 'c' , CodeMirror . Vim . getOption ( 'testopt' , cm ) ) ; //local || global
eq ( 'c' , CodeMirror . Vim . getOption ( 'testopt' , cm , { scope : 'local' } ) ) ; // local
eq ( 'c' , CodeMirror . Vim . getOption ( 'testopt' , cm , { scope : 'global' } ) ) ; // global
eq ( 'c' , CodeMirror . Vim . getOption ( 'testopt' ) ) ; // global
// Test setOption global
helpers . doEx ( 'setg testopt=d' )
eq ( 'c' , CodeMirror . Vim . getOption ( 'testopt' , cm ) ) ;
eq ( 'c' , CodeMirror . Vim . getOption ( 'testopt' , cm , { scope : 'local' } ) ) ;
eq ( 'd' , CodeMirror . Vim . getOption ( 'testopt' , cm , { scope : 'global' } ) ) ;
eq ( 'd' , CodeMirror . Vim . getOption ( 'testopt' ) ) ;
// Test setOption local
helpers . doEx ( 'setl testopt=e' )
eq ( 'e' , CodeMirror . Vim . getOption ( 'testopt' , cm ) ) ;
eq ( 'e' , CodeMirror . Vim . getOption ( 'testopt' , cm , { scope : 'local' } ) ) ;
eq ( 'd' , CodeMirror . Vim . getOption ( 'testopt' , cm , { scope : 'global' } ) ) ;
eq ( 'd' , CodeMirror . Vim . getOption ( 'testopt' ) ) ;
} )
testVim ( 'ex_set_filetype' , function ( cm , vim , helpers ) {
CodeMirror . defineMode ( 'test_mode' , function ( ) {
return { token : function ( stream ) {
stream . match ( /^\s+|^\S+/ ) ;
} } ;
} ) ;
CodeMirror . defineMode ( 'test_mode_2' , function ( ) {
return { token : function ( stream ) {
stream . match ( /^\s+|^\S+/ ) ;
} } ;
} ) ;
// Test mode is set.
helpers . doEx ( 'set filetype=test_mode' ) ;
eq ( 'test_mode' , cm . getMode ( ) . name ) ;
// Test 'ft' alias also sets mode.
helpers . doEx ( 'set ft=test_mode_2' ) ;
eq ( 'test_mode_2' , cm . getMode ( ) . name ) ;
} ) ;
testVim ( 'ex_set_filetype_null' , function ( cm , vim , helpers ) {
CodeMirror . defineMode ( 'test_mode' , function ( ) {
return { token : function ( stream ) {
stream . match ( /^\s+|^\S+/ ) ;
} } ;
} ) ;
cm . setOption ( 'mode' , 'test_mode' ) ;
// Test mode is set to null.
helpers . doEx ( 'set filetype=' ) ;
eq ( 'null' , cm . getMode ( ) . name ) ;
} ) ;
testVim ( 'mapclear' , function ( cm , vim , helpers ) {
CodeMirror . Vim . map ( 'w' , 'l' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
helpers . doKeys ( 'w' ) ;
helpers . assertCursorAt ( 0 , 1 ) ;
CodeMirror . Vim . mapclear ( 'visual' ) ;
helpers . doKeys ( 'v' , 'w' , 'v' ) ;
helpers . assertCursorAt ( 0 , 4 ) ;
helpers . doKeys ( 'w' ) ;
helpers . assertCursorAt ( 0 , 5 ) ;
CodeMirror . Vim . mapclear ( ) ;
} , { value : 'abc abc' } ) ;
testVim ( 'mapclear_context' , function ( cm , vim , helpers ) {
CodeMirror . Vim . map ( 'w' , 'l' , 'normal' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
helpers . doKeys ( 'w' ) ;
helpers . assertCursorAt ( 0 , 1 ) ;
CodeMirror . Vim . mapclear ( 'normal' ) ;
helpers . doKeys ( 'w' ) ;
helpers . assertCursorAt ( 0 , 4 ) ;
CodeMirror . Vim . mapclear ( ) ;
} , { value : 'abc abc' } ) ;
testVim ( 'ex_map_key2key' , function ( cm , vim , helpers ) {
helpers . doEx ( 'map a x' ) ;
helpers . doKeys ( 'a' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
eq ( 'bc' , cm . getValue ( ) ) ;
CodeMirror . Vim . mapclear ( ) ;
} , { value : 'abc' } ) ;
testVim ( 'ex_unmap_key2key' , function ( cm , vim , helpers ) {
helpers . doEx ( 'map a x' ) ;
helpers . doEx ( 'unmap a' ) ;
helpers . doKeys ( 'a' ) ;
eq ( 'vim-insert' , cm . getOption ( 'keyMap' ) ) ;
CodeMirror . Vim . mapclear ( ) ;
} , { value : 'abc' } ) ;
testVim ( 'ex_unmap_key2key_does_not_remove_default' , function ( cm , vim , helpers ) {
expectFail ( function ( ) {
helpers . doEx ( 'unmap a' ) ;
} ) ;
helpers . doKeys ( 'a' ) ;
eq ( 'vim-insert' , cm . getOption ( 'keyMap' ) ) ;
CodeMirror . Vim . mapclear ( ) ;
} , { value : 'abc' } ) ;
testVim ( 'ex_map_key2key_to_colon' , function ( cm , vim , helpers ) {
helpers . doEx ( 'map ; :' ) ;
var dialogOpened = false ;
cm . openDialog = function ( ) {
dialogOpened = true ;
}
helpers . doKeys ( ';' ) ;
eq ( dialogOpened , true ) ;
CodeMirror . Vim . mapclear ( ) ;
} ) ;
testVim ( 'ex_map_ex2key:' , function ( cm , vim , helpers ) {
helpers . doEx ( 'map :del x' ) ;
helpers . doEx ( 'del' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
eq ( 'bc' , cm . getValue ( ) ) ;
CodeMirror . Vim . mapclear ( ) ;
} , { value : 'abc' } ) ;
testVim ( 'ex_map_ex2ex' , function ( cm , vim , helpers ) {
helpers . doEx ( 'map :del :w' ) ;
var tmp = CodeMirror . commands . save ;
var written = false ;
var actualCm ;
CodeMirror . commands . save = function ( cm ) {
written = true ;
actualCm = cm ;
} ;
helpers . doEx ( 'del' ) ;
CodeMirror . commands . save = tmp ;
eq ( written , true ) ;
eq ( actualCm , cm ) ;
CodeMirror . Vim . mapclear ( ) ;
} ) ;
testVim ( 'ex_map_key2ex' , function ( cm , vim , helpers ) {
helpers . doEx ( 'map a :w' ) ;
var tmp = CodeMirror . commands . save ;
var written = false ;
var actualCm ;
CodeMirror . commands . save = function ( cm ) {
written = true ;
actualCm = cm ;
} ;
helpers . doKeys ( 'a' ) ;
CodeMirror . commands . save = tmp ;
eq ( written , true ) ;
eq ( actualCm , cm ) ;
CodeMirror . Vim . mapclear ( ) ;
} ) ;
testVim ( 'ex_map_key2key_visual_api' , function ( cm , vim , helpers ) {
CodeMirror . Vim . map ( 'b' , ':w' , 'visual' ) ;
var tmp = CodeMirror . commands . save ;
var written = false ;
var actualCm ;
CodeMirror . commands . save = function ( cm ) {
written = true ;
actualCm = cm ;
} ;
// Mapping should not work in normal mode.
helpers . doKeys ( 'b' ) ;
eq ( written , false ) ;
// Mapping should work in visual mode.
helpers . doKeys ( 'v' , 'b' ) ;
eq ( written , true ) ;
eq ( actualCm , cm ) ;
CodeMirror . commands . save = tmp ;
CodeMirror . Vim . mapclear ( ) ;
} ) ;
testVim ( 'ex_imap' , function ( cm , vim , helpers ) {
CodeMirror . Vim . map ( 'jk' , '<Esc>' , 'insert' ) ;
helpers . doKeys ( 'i' ) ;
is ( vim . insertMode ) ;
helpers . doKeys ( 'j' , 'k' ) ;
is ( ! vim . insertMode ) ;
cm . setCursor ( 0 , 1 ) ;
CodeMirror . Vim . map ( 'jj' , '<Esc>' , 'insert' ) ;
helpers . doKeys ( '<C-v>' , '2' , 'j' , 'l' , 'c' ) ;
helpers . doKeys ( 'f' , 'o' ) ;
eq ( '1fo4\n5fo8\nafodefg' , cm . getValue ( ) ) ;
helpers . doKeys ( 'j' , 'j' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '.' ) ;
eq ( 'foo4\nfoo8\nfoodefg' , cm . getValue ( ) ) ;
CodeMirror . Vim . mapclear ( ) ;
} , { value : '1234\n5678\nabcdefg' } ) ;
testVim ( 'ex_unmap_api' , function ( cm , vim , helpers ) {
CodeMirror . Vim . map ( '<Alt-X>' , 'gg' , 'normal' ) ;
is ( CodeMirror . Vim . handleKey ( cm , "<Alt-X>" , "normal" ) , "Alt-X key is mapped" ) ;
CodeMirror . Vim . unmap ( "<Alt-X>" , "normal" ) ;
is ( ! CodeMirror . Vim . handleKey ( cm , "<Alt-X>" , "normal" ) , "Alt-X key is unmapped" ) ;
CodeMirror . Vim . mapclear ( ) ;
} ) ;
// Testing registration of functions as ex-commands and mapping to <Key>-keys
testVim ( 'ex_api_test' , function ( cm , vim , helpers ) {
var res = false ;
var val = 'from' ;
CodeMirror . Vim . defineEx ( 'extest' , 'ext' , function ( cm , params ) {
if ( params . args ) val = params . args [ 0 ] ;
else res = true ;
} ) ;
helpers . doEx ( ':ext to' ) ;
eq ( val , 'to' , 'Defining ex-command failed' ) ;
CodeMirror . Vim . map ( '<C-CR><Space>' , ':ext' ) ;
helpers . doKeys ( '<C-CR>' , '<Space>' ) ;
is ( res , 'Mapping to key failed' ) ;
CodeMirror . Vim . mapclear ( ) ;
} ) ;
2020-10-02 13:05:50 +02:00
// Testing ex-commands with non-alpha names.
testVim ( 'ex_special_names' , function ( cm , vim , helpers ) {
var ran , val ;
var cmds = [ '!' , '!!' , '#' , '&' , '*' , '<' , '=' , '>' , '@' , '@@' , '~' , 'regtest1' , 'RT2' ] ;
cmds . forEach ( function ( name ) {
CodeMirror . Vim . defineEx ( name , '' , function ( cm , params ) {
ran = params . commandName ;
val = params . argString ;
} ) ;
helpers . doEx ( ':' + name ) ;
eq ( ran , name , 'Running ex-command failed' ) ;
helpers . doEx ( ':' + name + ' x' ) ;
eq ( val , ' x' , 'Running ex-command with param failed: ' + name ) ;
if ( /^\W+$/ . test ( name ) ) {
helpers . doEx ( ':' + name + 'y' ) ;
eq ( val , 'y' , 'Running ex-command with param failed: ' + name ) ;
}
else {
helpers . doEx ( ':' + name + '-y' ) ;
eq ( val , '-y' , 'Running ex-command with param failed: ' + name ) ;
}
if ( name !== '!' ) {
helpers . doEx ( ':' + name + '!' ) ;
eq ( ran , name , 'Running ex-command with bang failed' ) ;
eq ( val , '!' , 'Running ex-command with bang failed: ' + name ) ;
helpers . doEx ( ':' + name + '!z' ) ;
eq ( ran , name , 'Running ex-command with bang & param failed' ) ;
eq ( val , '!z' , 'Running ex-command with bang & param failed: ' + name ) ;
}
} ) ;
} ) ;
2019-07-28 14:57:52 +02:00
// For now, this test needs to be last because it messes up : for future tests.
testVim ( 'ex_map_key2key_from_colon' , function ( cm , vim , helpers ) {
helpers . doEx ( 'map : x' ) ;
helpers . doKeys ( ':' ) ;
helpers . assertCursorAt ( 0 , 0 ) ;
eq ( 'bc' , cm . getValue ( ) ) ;
CodeMirror . Vim . mapclear ( ) ;
} , { value : 'abc' } ) ;
testVim ( 'noremap' , function ( cm , vim , helpers ) {
CodeMirror . Vim . noremap ( ';' , 'l' ) ;
cm . setCursor ( 0 , 0 ) ;
eq ( 'wOrd1' , cm . getValue ( ) ) ;
// Mapping should work in normal mode.
helpers . doKeys ( ';' , 'r' , '1' ) ;
eq ( 'w1rd1' , cm . getValue ( ) ) ;
// Mapping will not work in insert mode because of no current fallback
// keyToKey mapping support.
helpers . doKeys ( 'i' , ';' , '<Esc>' ) ;
eq ( 'w;1rd1' , cm . getValue ( ) ) ;
// unmap all mappings
CodeMirror . Vim . mapclear ( ) ;
} , { value : 'wOrd1' } ) ;
testVim ( 'noremap_swap' , function ( cm , vim , helpers ) {
CodeMirror . Vim . noremap ( 'i' , 'a' , 'normal' ) ;
CodeMirror . Vim . noremap ( 'a' , 'i' , 'normal' ) ;
cm . setCursor ( 0 , 0 ) ;
// 'a' should act like 'i'.
helpers . doKeys ( 'a' ) ;
eqCursorPos ( Pos ( 0 , 0 ) , cm . getCursor ( ) ) ;
// ...and 'i' should act like 'a'.
helpers . doKeys ( '<Esc>' , 'i' ) ;
eqCursorPos ( Pos ( 0 , 1 ) , cm . getCursor ( ) ) ;
// unmap all mappings
CodeMirror . Vim . mapclear ( ) ;
} , { value : 'foo' } ) ;
testVim ( 'noremap_map_interaction' , function ( cm , vim , helpers ) {
// noremap should clobber map
CodeMirror . Vim . map ( ';' , 'l' ) ;
CodeMirror . Vim . noremap ( ';' , 'l' ) ;
CodeMirror . Vim . map ( 'l' , 'j' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( ';' ) ;
eqCursorPos ( Pos ( 0 , 1 ) , cm . getCursor ( ) ) ;
helpers . doKeys ( 'l' ) ;
eqCursorPos ( Pos ( 1 , 1 ) , cm . getCursor ( ) ) ;
// map should be able to point to a noremap
CodeMirror . Vim . map ( 'm' , ';' ) ;
helpers . doKeys ( 'm' ) ;
eqCursorPos ( Pos ( 1 , 2 ) , cm . getCursor ( ) ) ;
// unmap all mappings
CodeMirror . Vim . mapclear ( ) ;
} , { value : 'wOrd1\nwOrd2' } ) ;
testVim ( 'noremap_map_interaction2' , function ( cm , vim , helpers ) {
// map should point to the most recent noremap
CodeMirror . Vim . noremap ( ';' , 'l' ) ;
CodeMirror . Vim . map ( 'm' , ';' ) ;
CodeMirror . Vim . noremap ( ';' , 'h' ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( 'l' ) ;
eqCursorPos ( Pos ( 0 , 1 ) , cm . getCursor ( ) ) ;
helpers . doKeys ( 'm' ) ;
eqCursorPos ( Pos ( 0 , 0 ) , cm . getCursor ( ) ) ;
// unmap all mappings
CodeMirror . Vim . mapclear ( ) ;
} , { value : 'wOrd1\nwOrd2' } ) ;
// Test event handlers
testVim ( 'beforeSelectionChange' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 100 ) ;
eqCursorPos ( cm . getCursor ( 'head' ) , cm . getCursor ( 'anchor' ) ) ;
} , { value : 'abc' } ) ;
testVim ( 'increment_binary' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 4 ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '0b001' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '0b010' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0b001' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0b000' , cm . getValue ( ) ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '0b001' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '0b010' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0b001' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0b000' , cm . getValue ( ) ) ;
} , { value : '0b000' } ) ;
testVim ( 'increment_octal' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 2 ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '001' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '002' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '003' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '004' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '005' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '006' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '007' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '010' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '007' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '006' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '005' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '004' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '003' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '002' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '001' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '000' , cm . getValue ( ) ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '001' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '002' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '001' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '000' , cm . getValue ( ) ) ;
} , { value : '000' } ) ;
testVim ( 'increment_decimal' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 2 ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '101' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '102' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '103' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '104' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '105' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '106' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '107' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '108' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '109' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '110' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '109' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '108' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '107' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '106' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '105' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '104' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '103' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '102' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '101' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '100' , cm . getValue ( ) ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '101' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '102' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '101' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '100' , cm . getValue ( ) ) ;
} , { value : '100' } ) ;
testVim ( 'increment_decimal_single_zero' , function ( cm , vim , helpers ) {
helpers . doKeys ( '<C-a>' ) ;
eq ( '1' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '2' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '3' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '4' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '5' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '6' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '7' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '8' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '9' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '10' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '9' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '8' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '7' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '6' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '5' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '4' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '3' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '2' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '1' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0' , cm . getValue ( ) ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '1' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '2' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '1' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0' , cm . getValue ( ) ) ;
} , { value : '0' } ) ;
testVim ( 'increment_hexadecimal' , function ( cm , vim , helpers ) {
cm . setCursor ( 0 , 2 ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '0x1' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '0x2' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '0x3' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '0x4' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '0x5' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '0x6' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '0x7' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '0x8' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '0x9' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '0xa' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '0xb' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '0xc' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '0xd' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '0xe' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '0xf' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '0x10' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0x0f' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0x0e' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0x0d' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0x0c' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0x0b' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0x0a' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0x09' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0x08' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0x07' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0x06' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0x05' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0x04' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0x03' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0x02' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0x01' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0x00' , cm . getValue ( ) ) ;
cm . setCursor ( 0 , 0 ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '0x01' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-a>' ) ;
eq ( '0x02' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0x01' , cm . getValue ( ) ) ;
helpers . doKeys ( '<C-x>' ) ;
eq ( '0x00' , cm . getValue ( ) ) ;
} , { value : '0x0' } ) ;