forked from Botanical/BotanJS
Partial % motion
This commit is contained in:
parent
3f687cb704
commit
799a911e06
@ -281,6 +281,30 @@
|
|||||||
break
|
break
|
||||||
|
|
||||||
case SHIFT + _5: // %, Find next item
|
case SHIFT + _5: // %, Find next item
|
||||||
|
var analyzer = this.__vimArea.contentAnalyzer;
|
||||||
|
|
||||||
|
/** @type {Components.Vim.Syntax.TokenMatch} */
|
||||||
|
var bracketMatch = analyzer.bracketAt( ccur.aPos );
|
||||||
|
|
||||||
|
if( bracketMatch.open == -1 )
|
||||||
|
{
|
||||||
|
beep();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var d = 1;
|
||||||
|
var at = bracketMatch.close;
|
||||||
|
if( bracketMatch.selected == at )
|
||||||
|
{
|
||||||
|
d = -1;
|
||||||
|
at = bracketMatch.open;
|
||||||
|
}
|
||||||
|
|
||||||
|
while( ccur.aPos != at )
|
||||||
|
{
|
||||||
|
ccur.moveX( d, true );
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case T: // To
|
case T: // To
|
||||||
break;
|
break;
|
||||||
@ -291,6 +315,8 @@
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var analyzer = this.__vimArea.contentAnalyzer;
|
||||||
|
|
||||||
this.__cMovement = true;
|
this.__cMovement = true;
|
||||||
// Word boundary
|
// Word boundary
|
||||||
this.__comp( kCode, function(){
|
this.__comp( kCode, function(){
|
||||||
@ -307,6 +333,7 @@
|
|||||||
}, SHIFT + S_BRACKET_L );
|
}, SHIFT + S_BRACKET_L );
|
||||||
this.__comp( kCode, function(){
|
this.__comp( kCode, function(){
|
||||||
debug.Info( "Bracket boundary }" );
|
debug.Info( "Bracket boundary }" );
|
||||||
|
analyzer.bracketAt( ccur.aPos );
|
||||||
}, SHIFT + S_BRACKET_R );
|
}, SHIFT + S_BRACKET_R );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -88,9 +88,8 @@
|
|||||||
// Set by VimArea
|
// Set by VimArea
|
||||||
Cursor.prototype.Vim;
|
Cursor.prototype.Vim;
|
||||||
|
|
||||||
// Can only be 1, -1
|
// 0 will be treated as default ( 1 )
|
||||||
// 0 will be treated as undefined
|
Cursor.prototype.moveX = function( d, penetrate, phantomSpace )
|
||||||
Cursor.prototype.moveX = function( d, penentrate, phantomSpace )
|
|
||||||
{
|
{
|
||||||
var x = this.pX;
|
var x = this.pX;
|
||||||
|
|
||||||
@ -101,7 +100,7 @@
|
|||||||
|
|
||||||
var buffs = this.feeder.lineBuffers;
|
var buffs = this.feeder.lineBuffers;
|
||||||
|
|
||||||
if( penentrate )
|
if( penetrate )
|
||||||
{
|
{
|
||||||
if( x < 0 && ( 0 < this.feeder.panY || 0 < this.Y ) )
|
if( x < 0 && ( 0 < this.feeder.panY || 0 < this.Y ) )
|
||||||
{
|
{
|
||||||
@ -118,15 +117,41 @@
|
|||||||
|
|
||||||
var c = content[ x ];
|
var c = content[ x ];
|
||||||
|
|
||||||
// Include empty lines befor cursor end
|
// Motion includes empty lines before cursor end
|
||||||
if( ( phantomSpace && cLen - 1 <= x ) || ( cLen == 1 && c == undefined ) )
|
if( ( phantomSpace && cLen - 1 <= x ) || ( cLen == 1 && c == undefined ) )
|
||||||
{
|
{
|
||||||
x = 0 < d ? cLen - 1 : 0;
|
if( 0 < d )
|
||||||
|
{
|
||||||
|
x = cLen - 1;
|
||||||
|
if( penetrate )
|
||||||
|
{
|
||||||
|
this.X = 0;
|
||||||
|
this.moveY( 1 );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// ( 2 < cLen ) Exclude empty lines at cursor end
|
// ( 2 < cLen ) motion excludes empty lines at cursor end
|
||||||
else if( ( 2 <= cLen && x == cLen - 1 && c == " " ) || c == undefined )
|
else if( ( 2 <= cLen && x == cLen - 1 && c == " " ) || c == undefined )
|
||||||
{
|
{
|
||||||
x = 0 < d ? cLen - 2 : 0;
|
if( 0 < d )
|
||||||
|
{
|
||||||
|
x = cLen - 2;
|
||||||
|
if( penetrate )
|
||||||
|
{
|
||||||
|
this.X = 0;
|
||||||
|
this.moveY( 1 );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if( c == "\n" )
|
else if( c == "\n" )
|
||||||
{
|
{
|
||||||
@ -174,7 +199,7 @@
|
|||||||
this.feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );
|
this.feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );
|
||||||
};
|
};
|
||||||
|
|
||||||
Cursor.prototype.moveY = function( d, penentrate )
|
Cursor.prototype.moveY = function( d, penetrate )
|
||||||
{
|
{
|
||||||
var i;
|
var i;
|
||||||
var Y = this.Y + d;
|
var Y = this.Y + d;
|
||||||
@ -197,7 +222,7 @@
|
|||||||
{
|
{
|
||||||
var feeder = this.feeder;
|
var feeder = this.feeder;
|
||||||
|
|
||||||
if( penentrate )
|
if( penetrate )
|
||||||
{
|
{
|
||||||
feeder.pan( undefined, Y - moreAt );
|
feeder.pan( undefined, Y - moreAt );
|
||||||
}
|
}
|
||||||
|
267
botanjs/src/Components/Vim/Syntax/Analyzer.js
Normal file
267
botanjs/src/Components/Vim/Syntax/Analyzer.js
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
(function(){
|
||||||
|
var ns = __namespace( "Components.Vim.Syntax" );
|
||||||
|
|
||||||
|
/** @type {System.Debug} */
|
||||||
|
var debug = __import( "System.Debug" );
|
||||||
|
|
||||||
|
var TOK_OPEN = 0;
|
||||||
|
var TOK_CLOSED = 1;
|
||||||
|
var TOK_LEVEL = 2;
|
||||||
|
var TOK_PARENT = 3;
|
||||||
|
|
||||||
|
var TOK_SEP = "\n";
|
||||||
|
|
||||||
|
var TOK_JOIN = function( a, b ) { return a + TOK_SEP + b; };
|
||||||
|
|
||||||
|
/*{{{ Private Class */
|
||||||
|
var TokenPairs = function( tok, content, esc )
|
||||||
|
{
|
||||||
|
var l = content.length;
|
||||||
|
var toks = tok.split( TOK_SEP );
|
||||||
|
var openToken = toks[0];
|
||||||
|
var closeToken = toks[1];
|
||||||
|
|
||||||
|
var opStack = [];
|
||||||
|
|
||||||
|
var unmatchedEd = [];
|
||||||
|
|
||||||
|
var lv = 0;
|
||||||
|
|
||||||
|
var pairs = [];
|
||||||
|
|
||||||
|
var lvUp = function( i )
|
||||||
|
{
|
||||||
|
opStack[ lv ] = i;
|
||||||
|
lv ++;
|
||||||
|
};
|
||||||
|
|
||||||
|
var lvDown = function( i )
|
||||||
|
{
|
||||||
|
if( lv == 0 )
|
||||||
|
{
|
||||||
|
// Cannot level down. i.e. Unmatched tokens
|
||||||
|
unmatchedEd.push( i );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var Token = [];
|
||||||
|
Token[ TOK_OPEN ] = opStack[ -- lv ];
|
||||||
|
Token[ TOK_CLOSED ] = i;
|
||||||
|
Token[ TOK_LEVEL ] = lv;
|
||||||
|
Token[ TOK_PARENT ] = 0 < lv ? opStack[ lv - 1 ] : -1;
|
||||||
|
|
||||||
|
pairs.push( Token );
|
||||||
|
};
|
||||||
|
|
||||||
|
var opLen = openToken.length;
|
||||||
|
var edLen = closeToken.length;
|
||||||
|
for( var i = 0; i < l; i ++ )
|
||||||
|
{
|
||||||
|
var opTok = content.substr( i, opLen );
|
||||||
|
var edTok = content.substr( i, edLen );
|
||||||
|
if( opTok == openToken )
|
||||||
|
{
|
||||||
|
lvUp( i );
|
||||||
|
i += opLen - 1;
|
||||||
|
}
|
||||||
|
else if( edTok == closeToken )
|
||||||
|
{
|
||||||
|
lvDown( i );
|
||||||
|
i += edLen - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( unmatchedEd.length )
|
||||||
|
{
|
||||||
|
debug.Info( "Unmatched opening \"" + openToken + "\"@" + unmatchedEd.join( ", " ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( 0 < lv )
|
||||||
|
{
|
||||||
|
debug.Info( "Unmatched closing \"" + closeToken + "\"@" + opStack.slice( 0, lv ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
this.__pairs = pairs;
|
||||||
|
this.token = toks;
|
||||||
|
};
|
||||||
|
|
||||||
|
TokenPairs.prototype.token = "";
|
||||||
|
|
||||||
|
TokenPairs.prototype.matched = function()
|
||||||
|
{
|
||||||
|
return this.__pairs.sort(
|
||||||
|
function( a, b ) { return a[ TOK_OPEN ] - b[ TOK_OPEN ]; }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
TokenPairs.prototype.find = function( pos, state )
|
||||||
|
{
|
||||||
|
if( state == undefined ) state = TOK_OPEN;
|
||||||
|
|
||||||
|
var pairs = this.__pairs;
|
||||||
|
var l = pairs.length;
|
||||||
|
|
||||||
|
for( var i = 0; i < l; i ++ )
|
||||||
|
{
|
||||||
|
var pair = pairs[i];
|
||||||
|
if( pair[ state ] == pos )
|
||||||
|
{
|
||||||
|
return pair;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
/* End Private Class }}}*/
|
||||||
|
|
||||||
|
var Analyzer = function( feeder )
|
||||||
|
{
|
||||||
|
/* @type {Components.Vim.LineFeeder} */
|
||||||
|
this.__feeder = feeder;
|
||||||
|
this.__tokpairs = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
Analyzer.prototype.bracketAt = function( p )
|
||||||
|
{
|
||||||
|
var c = this.__feeder.content;
|
||||||
|
var tokState = TOK_CLOSED;
|
||||||
|
|
||||||
|
var BracketPairs = null;
|
||||||
|
var cTok = c[ p ];
|
||||||
|
|
||||||
|
switch( cTok )
|
||||||
|
{
|
||||||
|
case "{": tokState = TOK_OPEN;
|
||||||
|
case "}":
|
||||||
|
BracketPairs = this.GetPairs( TOK_JOIN( "{", "}" ) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "[": tokState = TOK_OPEN;
|
||||||
|
case "]":
|
||||||
|
BracketPairs = this.GetPairs( TOK_JOIN( "[", "]" ) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "(": tokState = TOK_OPEN;
|
||||||
|
case ")":
|
||||||
|
BracketPairs = this.GetPairs( TOK_JOIN( "(", ")" ) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "/":
|
||||||
|
if( c[ p - 1 ] == "*" )
|
||||||
|
{
|
||||||
|
cTok = "*/";
|
||||||
|
p --;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if( c[ p + 1 ] == "*" )
|
||||||
|
{
|
||||||
|
cTok = "/*";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return new TokenMatch();
|
||||||
|
|
||||||
|
case "*":
|
||||||
|
if( c[ p - 1 ] == "/" )
|
||||||
|
{
|
||||||
|
cTok = "/*";
|
||||||
|
p --;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if( c[ p + 1 ] == "/" )
|
||||||
|
{
|
||||||
|
cTok = "*/";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return new TokenMatch();
|
||||||
|
|
||||||
|
default:
|
||||||
|
return new TokenMatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Long Switch
|
||||||
|
if( !BracketPairs ) switch( cTok )
|
||||||
|
{
|
||||||
|
case "/*": tokState = TOK_OPEN;
|
||||||
|
case "*/":
|
||||||
|
BracketPairs = this.GetPairs( TOK_JOIN( "/*", "*/" ) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return new TokenMatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
var SetParent = function( pair )
|
||||||
|
{
|
||||||
|
if( !pair ) throw new Error( "Parent not found" );
|
||||||
|
|
||||||
|
var tMatch = new TokenMatch();
|
||||||
|
tMatch.__level = pair[ TOK_LEVEL ];
|
||||||
|
tMatch.__open = pair[ TOK_OPEN ];
|
||||||
|
tMatch.__close = pair[ TOK_CLOSED ];
|
||||||
|
|
||||||
|
if( -1 < pair[ TOK_PARENT ] )
|
||||||
|
{
|
||||||
|
var rPair = BracketPairs.find( pair[ TOK_PARENT ] );
|
||||||
|
tMatch.__parent = SetParent( rPair );
|
||||||
|
}
|
||||||
|
|
||||||
|
return tMatch;
|
||||||
|
};
|
||||||
|
|
||||||
|
var rPair = BracketPairs.find( p, tokState );
|
||||||
|
var tMatch = SetParent( rPair )
|
||||||
|
tMatch.__selected = p;
|
||||||
|
|
||||||
|
return tMatch;
|
||||||
|
};
|
||||||
|
|
||||||
|
Analyzer.prototype.GetPairs = function( def, reload )
|
||||||
|
{
|
||||||
|
if( !reload && this.__tokpairs[ def ] )
|
||||||
|
{
|
||||||
|
return this.__tokpairs[ def ];
|
||||||
|
}
|
||||||
|
|
||||||
|
var c = this.__feeder.content;
|
||||||
|
var pairs = new TokenPairs( def, c );
|
||||||
|
|
||||||
|
this.__tokpairs[ def ] = pairs;
|
||||||
|
|
||||||
|
return pairs;
|
||||||
|
};
|
||||||
|
|
||||||
|
Analyzer.prototype.quoteAt = function( p )
|
||||||
|
{
|
||||||
|
var c = this.__feeder.content;
|
||||||
|
switch( c[ p ] )
|
||||||
|
{
|
||||||
|
case "`":
|
||||||
|
case "\"":
|
||||||
|
case "\'":
|
||||||
|
default:
|
||||||
|
return {
|
||||||
|
level: 0
|
||||||
|
, open: -1
|
||||||
|
, close: -1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var TokenMatch = function()
|
||||||
|
{
|
||||||
|
this.__open = -1;
|
||||||
|
this.__close = -1;
|
||||||
|
this.__selected = -1;
|
||||||
|
this.__level = -1;
|
||||||
|
this.__parent = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
__readOnly( TokenMatch.prototype, "parent", function() { return this.__parent; } );
|
||||||
|
__readOnly( TokenMatch.prototype, "open", function() { return this.__open; } );
|
||||||
|
__readOnly( TokenMatch.prototype, "close", function() { return this.__close; } );
|
||||||
|
__readOnly( TokenMatch.prototype, "level", function() { return this.__level; } );
|
||||||
|
__readOnly( TokenMatch.prototype, "selected", function() { return this.__selected; } );
|
||||||
|
|
||||||
|
ns[ NS_EXPORT ]( EX_CLASS, "Analyzer", Analyzer );
|
||||||
|
ns[ NS_EXPORT ]( EX_CLASS, "TokenMatch", TokenMatch );
|
||||||
|
})();
|
@ -11,7 +11,9 @@
|
|||||||
var debug = __import( "System.Debug" );
|
var debug = __import( "System.Debug" );
|
||||||
|
|
||||||
/** @type {Components.Vim.State.Registers} */
|
/** @type {Components.Vim.State.Registers} */
|
||||||
var Registers = __import( "Components.Vim.State.Registers" );
|
var Registers = __import( "Components.Vim.State.Registers" );
|
||||||
|
/** @type {Components.Vim.Syntax.Analyzer} */
|
||||||
|
var SyntaxAnalyzer = __import( "Components.Vim.Syntax.Analyzer" );
|
||||||
|
|
||||||
/** @type {Components.Vim.LineFeeder} */
|
/** @type {Components.Vim.LineFeeder} */
|
||||||
var LineFeeder = ns[ NS_INVOKE ]( "LineFeeder" );
|
var LineFeeder = ns[ NS_INVOKE ]( "LineFeeder" );
|
||||||
@ -94,6 +96,7 @@
|
|||||||
|
|
||||||
// Content feeder
|
// Content feeder
|
||||||
var cfeeder = new LineFeeder( cRange, c );
|
var cfeeder = new LineFeeder( cRange, c );
|
||||||
|
var contentAnalyzer = new SyntaxAnalyzer( cfeeder );
|
||||||
|
|
||||||
// Feed the contents to content feeder
|
// Feed the contents to content feeder
|
||||||
// This "\n" fixes the last line "\n" not displaying
|
// This "\n" fixes the last line "\n" not displaying
|
||||||
@ -132,6 +135,7 @@
|
|||||||
Update();
|
Update();
|
||||||
|
|
||||||
this.contentFeeder = cfeeder;
|
this.contentFeeder = cfeeder;
|
||||||
|
this.contentAnalyzer = contentAnalyzer;
|
||||||
this.statusFeeder = sfeeder;
|
this.statusFeeder = sfeeder;
|
||||||
this.statusBar = statusBar;
|
this.statusBar = statusBar;
|
||||||
this.registers = new Registers();
|
this.registers = new Registers();
|
||||||
|
7
botanjs/src/externs/Components.Vim.Syntax.Analyzer.js
Normal file
7
botanjs/src/externs/Components.Vim.Syntax.Analyzer.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
/** @constructor */
|
||||||
|
Components.Vim.Syntax.Analyzer = function(){};
|
||||||
|
|
||||||
|
/** @type Function */
|
||||||
|
Components.Vim.Syntax.Analyzer.bracketAt;
|
||||||
|
/** @type Function */
|
||||||
|
Components.Vim.Syntax.Analyzer.quoteAt;
|
14
botanjs/src/externs/Components.Vim.Syntax.TokenMatch.js
Normal file
14
botanjs/src/externs/Components.Vim.Syntax.TokenMatch.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/** @constructor */
|
||||||
|
Components.Vim.Syntax.TokenMatch = function(){};
|
||||||
|
|
||||||
|
/** @type {Components.Vim.Syntax.TokenMatch} */
|
||||||
|
Components.Vim.Syntax.TokenMatch.parent;
|
||||||
|
|
||||||
|
/** @type Number */
|
||||||
|
Components.Vim.Syntax.TokenMatch.open;
|
||||||
|
/** @type Number */
|
||||||
|
Components.Vim.Syntax.TokenMatch.close;
|
||||||
|
/** @type Number */
|
||||||
|
Components.Vim.Syntax.TokenMatch.level;
|
||||||
|
/** @type Number */
|
||||||
|
Components.Vim.Syntax.TokenMatch.selected;
|
2
botanjs/src/externs/Components.Vim.Syntax.js
Normal file
2
botanjs/src/externs/Components.Vim.Syntax.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/** @object */
|
||||||
|
Components.Vim.Syntax = {};
|
@ -3,6 +3,8 @@ Components.Vim.VimArea = function(){};
|
|||||||
|
|
||||||
/** @type {Components.Vim.LineFeeder} */
|
/** @type {Components.Vim.LineFeeder} */
|
||||||
Components.Vim.VimArea.contentFeeder;
|
Components.Vim.VimArea.contentFeeder;
|
||||||
|
/** @type {Components.Vim.Syntax.Analyzer} */
|
||||||
|
Components.Vim.VimArea.contentAnalyzer;
|
||||||
/** @type {Components.Vim.LineFeeder} */
|
/** @type {Components.Vim.LineFeeder} */
|
||||||
Components.Vim.VimArea.statusFeeder;
|
Components.Vim.VimArea.statusFeeder;
|
||||||
/** @type {Components.Vim.StatusBar} */
|
/** @type {Components.Vim.StatusBar} */
|
||||||
|
Loading…
Reference in New Issue
Block a user