@@ -200,24 +200,16 @@ define(function (require, exports, module) {
200200 "Shift-Tab" : "indentLess" ,
201201
202202 "Left" : function ( instance ) {
203- if ( ! self . _handleSoftTabNavigation ( - 1 , "moveH" ) ) {
204- CodeMirror . commands . goCharLeft ( instance ) ;
205- }
203+ self . _handleSoftTabNavigation ( - 1 , "moveH" ) ;
206204 } ,
207205 "Right" : function ( instance ) {
208- if ( ! self . _handleSoftTabNavigation ( 1 , "moveH" ) ) {
209- CodeMirror . commands . goCharRight ( instance ) ;
210- }
206+ self . _handleSoftTabNavigation ( 1 , "moveH" ) ;
211207 } ,
212208 "Backspace" : function ( instance ) {
213- if ( ! self . _handleSoftTabNavigation ( - 1 , "deleteH" ) ) {
214- CodeMirror . commands . delCharBefore ( instance ) ;
215- }
209+ self . _handleSoftTabNavigation ( - 1 , "deleteH" ) ;
216210 } ,
217211 "Delete" : function ( instance ) {
218- if ( ! self . _handleSoftTabNavigation ( 1 , "deleteH" ) ) {
219- CodeMirror . commands . delCharAfter ( instance ) ;
220- }
212+ self . _handleSoftTabNavigation ( 1 , "deleteH" ) ;
221213 } ,
222214 "Esc" : function ( instance ) {
223215 if ( self . getSelections ( ) . length > 1 ) {
@@ -448,59 +440,73 @@ define(function (require, exports, module) {
448440 /**
449441 * @private
450442 * Handle left arrow, right arrow, backspace and delete keys when soft tabs are used.
451- * @param {!CodeMirror } instance CodeMirror instance
452443 * @param {number } direction Direction of movement: 1 for forward, -1 for backward
453- * @param {function } functionName name of the CodeMirror function to call
454- * @return {boolean } true if key was handled
444+ * @param {string } functionName name of the CodeMirror function to call if we handle the key
455445 */
456446 Editor . prototype . _handleSoftTabNavigation = function ( direction , functionName ) {
457- var handled = false ,
458- instance = this . _codeMirror ;
447+ var instance = this . _codeMirror ,
448+ overallJump = null ;
459449
460450 if ( ! instance . getOption ( "indentWithTabs" ) ) {
461- var indentUnit = instance . getOption ( "indentUnit" ) ,
462- cursor = this . getCursorPos ( ) ,
463- jump = cursor . ch % indentUnit ,
464- line = instance . getLine ( cursor . line ) ;
465-
466- if ( direction === 1 ) {
467- jump = indentUnit - jump ;
468-
469- if ( cursor . ch + jump > line . length ) { // Jump would go beyond current line
470- return false ;
471- }
472-
473- if ( line . substr ( cursor . ch , jump ) . search ( / \S / ) === - 1 ) {
474- instance [ functionName ] ( jump , "char" ) ;
475- handled = true ;
476- }
477- } else {
478- // Quick exit if we are at the beginning of the line
479- if ( cursor . ch === 0 ) {
480- return false ;
451+ var indentUnit = instance . getOption ( "indentUnit" ) ;
452+
453+ _ . each ( this . getSelections ( ) , function ( sel ) {
454+ if ( CodeMirror . cmpPos ( sel . start , sel . end ) !== 0 ) {
455+ // This is a range - it will just collapse/be deleted regardless of the jump we set, so
456+ // we can just ignore it and continue. (We don't want to return false in this case since
457+ // we want to keep looking at other ranges.)
458+ return ;
481459 }
482460
483- // If we are on the tab boundary, jump by the full amount,
484- // but not beyond the start of the line.
485- if ( jump === 0 ) {
486- jump = indentUnit ;
487- }
461+ var cursor = sel . start ,
462+ jump = cursor . ch % indentUnit ,
463+ line = instance . getLine ( cursor . line ) ;
488464
489- // Search backwards to the first non-space character
490- var offset = line . substr ( cursor . ch - jump , jump ) . search ( / \s * $ / g) ;
465+ // Don't do any soft tab handling if there are non-whitespace characters before the cursor in
466+ // any of the selections.
467+ if ( line . substr ( 0 , cursor . ch ) . search ( / \S / ) !== - 1 ) {
468+ jump = null ;
469+ } else if ( direction === 1 ) { // right
470+ jump = indentUnit - jump ;
491471
492- if ( offset !== - 1 ) { // Adjust to jump to first non-space character
493- jump -= offset ;
472+ // Don't jump if it would take us past the end of the line, or if there are
473+ // non-whitespace characters within the jump distance.
474+ if ( cursor . ch + jump > line . length || line . substr ( cursor . ch , jump ) . search ( / \S / ) !== - 1 ) {
475+ jump = null ;
476+ }
477+ } else { // left
478+ // If we are on the tab boundary, jump by the full amount,
479+ // but not beyond the start of the line.
480+ if ( jump === 0 ) {
481+ jump = indentUnit ;
482+ }
483+ if ( cursor . ch - jump < 0 ) {
484+ jump = null ;
485+ } else {
486+ // We're moving left, so negate the jump.
487+ jump = - jump ;
488+ }
494489 }
495490
496- if ( jump > 0 ) {
497- instance [ functionName ] ( - jump , "char" ) ;
498- handled = true ;
491+ // Did we calculate a jump, and is this jump value either the first one or
492+ // consistent with all the other jumps? If so, we're good. Otherwise, bail
493+ // out of the foreach, since as soon as we hit an inconsistent jump we don't
494+ // have to look any further.
495+ if ( jump !== null &&
496+ ( overallJump === null || overallJump === jump ) ) {
497+ overallJump = jump ;
498+ } else {
499+ overallJump = null ;
500+ return false ;
499501 }
500- }
502+ } ) ;
501503 }
502-
503- return handled ;
504+
505+ if ( overallJump === null ) {
506+ // Just do the default move, which is one char in the given direction.
507+ overallJump = direction ;
508+ }
509+ instance [ functionName ] ( overallJump , "char" ) ;
504510 } ;
505511
506512 /**
0 commit comments