diff --git a/botanjs/src/Components/Vim/Actions/BUFFERS.js b/botanjs/src/Components/Vim/Actions/BUFFERS.js index 9248877..19ec446 100644 --- a/botanjs/src/Components/Vim/Actions/BUFFERS.js +++ b/botanjs/src/Components/Vim/Actions/BUFFERS.js @@ -48,10 +48,12 @@ var msg = ":buffers"; - for( var i in Insts ) + var l = Insts.length; + for( var i = 0; i < l; i ++ ) { /** @type {Components.Vim.VimArea} */ var inst = Insts[ i ]; + if( !inst ) continue; var b = inst.index + " "; var icur = inst.contentFeeder.cursor; diff --git a/botanjs/src/Components/Vim/Actions/EDITOR_COMMAND.js b/botanjs/src/Components/Vim/Actions/EDITOR_COMMAND.js index 7b2a6f1..78ff532 100644 --- a/botanjs/src/Components/Vim/Actions/EDITOR_COMMAND.js +++ b/botanjs/src/Components/Vim/Actions/EDITOR_COMMAND.js @@ -79,6 +79,9 @@ case "registers": out[ CMD_TYPE ] = "REGISTERS"; break; + case "marks": + out[ CMD_TYPE ] = "MARKS"; + break; case "ver": case "version": out[ CMD_TYPE ] = "VERSION"; @@ -90,6 +93,13 @@ case "varec": out[ CMD_TYPE ] = "VA_REC"; break; + + case "": // Range jumping + pattern.push( true ); + case "p": + allowRange = true; + out[ CMD_TYPE ] = "PRINT"; + break; } if( range !== "" ) diff --git a/botanjs/src/Components/Vim/Actions/JOIN_LINES.js b/botanjs/src/Components/Vim/Actions/JOIN_LINES.js index 4f21af6..4362765 100644 --- a/botanjs/src/Components/Vim/Actions/JOIN_LINES.js +++ b/botanjs/src/Components/Vim/Actions/JOIN_LINES.js @@ -66,7 +66,10 @@ var content = feeder.content; - contentUndo = feeder.content.substring( start, end ); + var l = content.length; + while( "\t ".indexOf( content[ end ] ) != -1 && end < l ) end ++; + + contentUndo = content.substring( start, end ); feeder.content = content.substring( 0, start ) + " " + content.substr( end ); } diff --git a/botanjs/src/Components/Vim/Actions/MARKS.js b/botanjs/src/Components/Vim/Actions/MARKS.js new file mode 100644 index 0000000..4ffe01f --- /dev/null +++ b/botanjs/src/Components/Vim/Actions/MARKS.js @@ -0,0 +1,83 @@ +(function(){ + var ns = __namespace( "Components.Vim.Actions" ); + + /** @type {System.Debug} */ + var debug = __import( "System.Debug" ); + + var VimError = __import( "Components.Vim.Error" ); + var Mesg = __import( "Components.Vim.Message" ); + + /** @type {System.Debug} */ + var Marks = __import( "Components.Vim.State.Marks" ); + var Keys = Marks.Keys; + + /** @type {Components.Vim.IAction} */ + var MARKS = function( Cursor ) + { + /** @type {Components.Vim.Cursor} */ + this.__cursor = Cursor; + this.__msg = ""; + Cursor.suppressEvent(); + }; + + MARKS.prototype.dispose = function() + { + this.__cursor.unsuppressEvent(); + }; + + MARKS.prototype.handler = function( e, p ) + { + e.preventDefault(); + + /** @type {Components.Vim.State.Marks} */ + var marks = e.target.marks; + + var msg = ":marks"; + + /** + * Regarding to marks 0-9, from Vim docs + * Numbered marks '0 to '9 are quite different. They can not be set directly. + * They are only present when using a viminfo file viminfo-file. Basically '0 + * is the location of the cursor when you last exited Vim, '1 the last but one + * time, etc. Use the "r" flag in 'viminfo' to specify files for which no + * Numbered mark should be stored. See viminfo-file-marks. + * TODO: Need to redefine marks 0-9 + **/ + + // Fuck this, use silly paddings + msg += "\nmark line col file/text"; + + var feeder = this.__cursor.feeder; + for( var i = 0, j = Keys[ i ]; j != undefined; i ++, j = Keys[ i ] ) + { + var r = marks.get( j ); + if( !r ) continue; + + var line = ( r[0] + 1 ) + ""; + var col = ( r[1] + 1 ) + ""; + var t = feeder.line( r[0] - 1 ).replace( /^[\t ]+/, "" ); + + var ll = 4 - line.length; + for( var il = 0; il < ll; il ++ ) line = " " + line; + + var ll = 3 - col.length; + for( var il = 0; il < ll; il ++ ) col = " " + col; + + msg += "\n " + j + " " + line + " " + col + " " + t; + } + + var lastLine = Mesg( "WAIT_FOR_INPUT" ); + + var l = this.__cursor.feeder.firstBuffer.cols; + for( var i = msg.length; i < l; i ++ ) msg += " "; + + this.__msg = msg + "\n" + lastLine; + }; + + MARKS.prototype.getMessage = function() + { + return this.__msg; + }; + + ns[ NS_EXPORT ]( EX_CLASS, "MARKS", MARKS ); +})(); diff --git a/botanjs/src/Components/Vim/Actions/PRINT.js b/botanjs/src/Components/Vim/Actions/PRINT.js new file mode 100644 index 0000000..7e8a9ed --- /dev/null +++ b/botanjs/src/Components/Vim/Actions/PRINT.js @@ -0,0 +1,48 @@ +(function(){ + var ns = __namespace( "Components.Vim.Actions" ); + + /** @type {System.Debug} */ + var debug = __import( "System.Debug" ); + + /** @type {Components.Vim.IAction} */ + var PRINT = function( Cursor ) + { + /** @type {Components.Vim.Cursor} */ + this.__cursor = Cursor; + this.__msg = ""; + }; + + PRINT.prototype.dispose = function() { }; + PRINT.prototype.handler = function( e, args, range ) + { + e.preventDefault(); + + if( args[0] === true ) + { + switch( range ) + { + case "%": + case "$": + this.__cursor.moveY( Number.MAX_VALUE ); + return; + case ".": + this.__cursor.lineStart( true ); + break; + case "": + default: + var lineNum = parseInt( range ) - 1; + if( lineNum ) + { + this.__cursor.gotoLine( 0 < lineNum ? lineNum : 0 ); + } + } + } + }; + + PRINT.prototype.getMessage = function() + { + return this.__msg; + }; + + ns[ NS_EXPORT ]( EX_CLASS, "PRINT", PRINT ); +})(); diff --git a/botanjs/src/Components/Vim/Actions/VISUAL.js b/botanjs/src/Components/Vim/Actions/VISUAL.js index 3bdb8d3..6770cac 100644 --- a/botanjs/src/Components/Vim/Actions/VISUAL.js +++ b/botanjs/src/Components/Vim/Actions/VISUAL.js @@ -182,10 +182,13 @@ startLine.aPos = startLine.aEnd; } } - // Cursor position adjustment - // this swap the cursor direction from LTR to RTL - // i.e. treat all delete as "e<----s" flow - // to keep the cursor position as the top on UNDO / REDO + + /** + * Content Modifier: + * This swaps the cursor direction from LTR to RTL + * i.e. treat all delete as "e<----s" flow to keep + * the cursor position as the top on UNDO / REDO + **/ var IsContMod = ~[ DELETE, PUT ].indexOf( Action.constructor ); if( IsContMod && startLine.aPos < cur.aPos ) { @@ -196,7 +199,12 @@ Action.handler( e, startLine.aPos, lineMode ); - if( !IsContMod ) + /** + * Cursor Modifier: + * Whether the cursor position is already handled + **/ + var IsCurMod = ~[ DELETE, PUT, SHIFT_LINES ].indexOf( Action.constructor ); + if( !IsCurMod ) { cur.moveTo( startLine.aPos ); } diff --git a/botanjs/src/Components/Vim/Controls.js b/botanjs/src/Components/Vim/Controls.js index 5f4e4d7..7057be3 100644 --- a/botanjs/src/Components/Vim/Controls.js +++ b/botanjs/src/Components/Vim/Controls.js @@ -136,6 +136,7 @@ case ")": Mod = SHIFT; case "0": kCode = Mod + _0; break; case "<": Mod = SHIFT; case ",": kCode = Mod + COMMA; break; case ">": Mod = SHIFT; case ".": kCode = Mod + FULLSTOP; break; + case "\"": Mod = SHIFT; case "'": kCode = Mod + QUOTE; break; default: throw new Error( "Unsupport keys: " + str ); @@ -477,16 +478,17 @@ { var kCode = e.keyCode; - if( this.__cMovement ) + if( this.__captureComp ) { if( !e.ModKeys ) { this.__composite( e ); - this.__cMovement = false; + this.__captureComp = false; return true; } } + var inst = this.__vimArea; var ccur = this.__ccur; var cfeeder = ccur.feeder; @@ -609,10 +611,22 @@ break; + case M: + this.__captureComp = true; + + var marks = this.__vimArea.marks; + this.__composite( e, function( e2 ) { + var line = ccur.getLine().lineNum; + if( !marks.set( e2.key, line, ccur.aX ) ) + { + beep(); + } + }, ANY_KEY ); + break; case SHIFT + T: // To case T: // To - this.__cMovement = true; + this.__captureComp = true; this.__composite( e, function( e2 ) { var oX = ccur.X; @@ -631,7 +645,7 @@ break; case SHIFT + F: // To case F: // To - this.__cMovement = true; + this.__captureComp = true; this.__composite( e, function( e2 ) { ccur.openRunAction( "TO", e, e2 ); @@ -658,7 +672,7 @@ var analyzer = this.__vimArea.contentAnalyzer; - this.__cMovement = true; + this.__captureComp = true; // Word boundary this.__composite( e, function( e2 ) { @@ -702,7 +716,7 @@ case G: - this.__cMovement = true; + this.__captureComp = true; // Go to top this.__composite( e, function() { @@ -774,11 +788,35 @@ break; case SLASH: // "/" Search movement - this.__cMovement = true; + this.__captureComp = true; this.__divedCCmd = new ExCommand( ccur, "/" ); this.__divedCCmd.handler( e ); break; + + case SHIFT + SEMI_COLON: // ":", only happens within action + if( !ccur.action ) + { + cursorHandled = false; + break; + } + + this.__captureComp = true; + + var exCmd = new ExCommand( ccur, ":" ); + exCmd.handler( e ); + + // Auto define range '< and '> + var cSel = ccur.position; + if( 1 < ( cSel.end - cSel.start ) ) + { + ActionEvent + .__createEventList( e.sender, "'<,'>" ) + .forEach( function( e2 ) { exCmd.handler( e2 ); } ); + } + + this.__divedCCmd = exCmd; + break; default: cursorHandled = false; } @@ -802,7 +840,7 @@ if( e.Escape ) { var b = false; - this.__cMovement = false; + this.__captureComp = false; if( this.__compositeReg ) { @@ -828,7 +866,7 @@ if( this.__divedCCmd.handler( e ) ) { this.__divedCCmd.dispose(); - this.__cMovement = false; + this.__captureComp = false; this.__divedCCmd = null; return; } @@ -839,7 +877,7 @@ var cfeeder = this.__cfeeder; var ccur = this.__ccur; - if( !this.__cMovement && ( !ccur.action || ccur.action.allowMovement ) ) + if( !this.__captureComp && ( !ccur.action || ccur.action.allowMovement ) ) { this.__modCommand( e ); if( e.canceled ) return; @@ -861,7 +899,10 @@ { var SubCommand = !this.__compositeReg; this.__cursorCommand( e, kCode ); - if( SubCommand && this.__compositeReg ) + + // Check if Sub / Dived composite command has been initiated + // within the CursorCommand + if( ( SubCommand && this.__compositeReg ) || this.__divedCCmd ) { e.preventDefault(); return; @@ -927,6 +968,18 @@ this.__range = null; }; + ActionEvent.__createEventList = function( sender, KeyDefs ) + { + var l = KeyDefs.length; + var List = []; + for( var i = 0; i < l; i ++ ) + { + List.push( new ActionEvent( sender, KeyDefs[ i ] ) ); + } + + return List; + }; + __readOnly( ActionEvent.prototype, "target", function() { return this.__target; } ); __readOnly( ActionEvent.prototype, "key", function() { return this.__key; } ); __readOnly( ActionEvent.prototype, "keyCode", function() { return this.__kCode; } ); diff --git a/botanjs/src/Components/Vim/Cursor.js b/botanjs/src/Components/Vim/Cursor.js index 25e858c..c1d7ceb 100644 --- a/botanjs/src/Components/Vim/Cursor.js +++ b/botanjs/src/Components/Vim/Cursor.js @@ -106,6 +106,8 @@ // Move to an absolute position Cursor.prototype.moveTo = function( aPos, phantomSpace, skipTabs ) { + this.__suppressUpdate(); + var content = this.feeder.content; var pline = this.getLine(); var lastLineNum = pline.lineNum; @@ -131,17 +133,18 @@ } var jumpY = expLineNum - lastLineNum; - if( jumpY ) - { - this.moveY( jumpY ); - - // Because moveTo is a direct jump function - // We'll auto reveal the target line here - if( this.feeder.moreAt == this.Y ) this.moveY( 1 ); - } + if( jumpY ) this.moveY( jumpY ); pline = this.getLine(); + // Because moveTo is a direct jump function + // We'll have to auto reveal the target line here + if( pline.lineNum != expLineNum ) + { + this.moveY( expLineNum - pline.lineNum ); + pline = this.getLine(); + } + var jumpX = aPos < lineStart ? lineStart - aPos : aPos - lineStart; var kX = jumpX - pline.content.length; @@ -159,6 +162,50 @@ this.moveX( - Number.MAX_VALUE, false, false, true ); this.moveX( jumpX, false, phantomSpace, skipTabs ); + + this.__unsuppressUpdate(); + }; + + // A line-only variant of moveTo, de-generalized for the sake of performance + Cursor.prototype.gotoLine = function( n ) + { + this.__suppressUpdate(); + + var content = this.feeder.content; + var pline = this.getLine(); + var lastLineNum = pline.lineNum; + + if( pline.placeholder ) + { + lastLineNum = 0; + this.Y = 0; + } + + var expLineNum = 0; + var lineStart = 0; + for( var i = content.indexOf( "\n" ); 0 <= i ; i = content.indexOf( "\n", i ) ) + { + if( expLineNum == n ) break; + lineStart = i; + i ++; + expLineNum ++; + } + + if( expLineNum < n ) n = expLineNum; + + var jumpY = expLineNum - lastLineNum; + if( jumpY ) this.moveY( jumpY ); + + pline = this.getLine(); + + if( pline.lineNum != expLineNum ) + { + this.moveY( expLineNum - pline.lineNum ); + } + + this.lineStart( true ); + + this.__unsuppressUpdate(); }; // 0 will be treated as default ( 1 ) @@ -319,7 +366,7 @@ else if( c == "\n" ) { x += d; - } + } // Wordwrap phantomSpace movement compensation on max filled lines if( feeder.wrap && boundary && !hasPhantomSpace && phantomSpace ) @@ -365,10 +412,12 @@ this.moveX( Number.MAX_VALUE, false, phantomSpace, true ); }; + // Because LineOffset is costly, suppress unnecessary calls Cursor.prototype.updatePosition = function() { - var feeder = this.feeder; - var P = this.X + LineOffset( feeder.lineBuffers, this.Y ) + this.__off; + if( 0 < this.__suppUpdate ) return; + + var P = this.X + LineOffset( this.feeder.lineBuffers, this.Y ) + this.__off; this.PStart = P; this.PEnd = P + 1; @@ -534,6 +583,13 @@ Cursor.prototype.suppressEvent = function() { ++ this.__suppEvt; }; Cursor.prototype.unsuppressEvent = function() { -- this.__suppEvt; }; + Cursor.prototype.__suppressUpdate = function() { ++ this.__suppUpdate; }; + Cursor.prototype.__unsuppressUpdate = function() + { + -- this.__suppUpdate; + this.updatePosition(); + }; + Cursor.prototype.getLine = function( display ) { var feeder = this.feeder; @@ -564,20 +620,7 @@ __readOnly( Cursor.prototype, "rawLine", function() { - var str = this.feeder.content; - var lineNum = this.getLine().lineNum - 1; - var i = str.indexOf( "\n" ), j = 0; - - for( ; 0 <= i; i = str.indexOf( "\n", i ), j ++ ) - { - if( lineNum == j ) break; - i ++; - } - - if( j == 0 && i == -1 ) i = 0; - - var end = str.indexOf( "\n", i + 1 ); - return str.substring( i + 1, end ); + return this.feeder.line( this.getLine().lineNum - 1 ); } ); // The position offset relative to current line @@ -598,7 +641,8 @@ // because phantomSpace is not a valid character // So we calculate along with the phantomSpace here var phantomSpace = X; - for( var i in lines ) + var lc = lines.length; + for( var i = 0; i < lc; i ++ ) { /** @type {Components.Vim.LineBuffer} */ var vline = lines[ i ]; diff --git a/botanjs/src/Components/Vim/LineFeeder.js b/botanjs/src/Components/Vim/LineFeeder.js index 4098773..b939daf 100644 --- a/botanjs/src/Components/Vim/LineFeeder.js +++ b/botanjs/src/Components/Vim/LineFeeder.js @@ -10,6 +10,7 @@ var Cursor = ns[ NS_INVOKE ]( "Cursor" ); var occurence = __import( "System.utils.Perf.CountSubstr" ); + var C_LINE = 0; var Feeder = function( rows, cols ) { @@ -35,6 +36,7 @@ this.cursor = new Cursor( this ); this.dispatcher = new EventDispatcher(); + this.__lineCache = []; this.__clseLine = null; this.__moreAt = -1; this.__rows = rows; @@ -42,7 +44,7 @@ Feeder.prototype.init = function( content, wrap ) { - this.content = content; + this.__content = content; this.setWrap( wrap ); this.firstBuffer.Push( content, this.wrap, 0 ); @@ -142,7 +144,7 @@ if( Y < 0 ) Y = 0; // Compensate the last "\n" content placeholder - var cont = this.content.slice( 0, -1 ); + var cont = this.__content.slice( 0, -1 ); if( 0 < Y ) { f = cont.indexOf( "\n" ); @@ -158,7 +160,7 @@ } } - this.firstBuffer.Push( this.content.substr( f + 1 ), this.wrap, i ); + this.firstBuffer.Push( this.__content.substr( f + 1 ), this.wrap, i ); this.panX = X; this.panY = Y; @@ -171,8 +173,27 @@ this.__softRender(); }; + Feeder.prototype.line = function( n ) + { + if( this.__lineCache[ n ] ) + return this.__lineCache[ n ]; + var str = this.__content; + var i = str.indexOf( "\n" ), j = 0; + + for( ; 0 <= i; i = str.indexOf( "\n", i ), j ++ ) + { + if( n == j ) break; + i ++; + } + + if( j == 0 && i == -1 ) i = 0; + + var end = str.indexOf( "\n", i + 1 ); + return ( this.__lineCache[ n ] = str.substring( i + 1, end ) ); + }; + __readOnly( Feeder.prototype, "linesTotal", function() { - return occurence( this.content, "\n" ); + return occurence( this.__content, "\n" ); } ); __readOnly( Feeder.prototype, "firstBuffer", function() { @@ -216,7 +237,7 @@ var i = l - X; do { - if( this.content[ i + 1 ] == "\t" ) tabs ++; + if( this.__content[ i + 1 ] == "\t" ) tabs ++; i ++; } while( i < l ) @@ -254,6 +275,15 @@ return pos; } ); + Object.defineProperty( Feeder.prototype, "content", { + get: function() { return this.__content; } + , set: function( v ) + { + this.__lineCache = []; + this.__content = v; + } + } ); + __readOnly( Feeder.prototype, "linesOccupied", function() { var line = this.firstBuffer; if( line.placeholder ) return 0; diff --git a/botanjs/src/Components/Vim/State/Marks.js b/botanjs/src/Components/Vim/State/Marks.js new file mode 100644 index 0000000..102af97 --- /dev/null +++ b/botanjs/src/Components/Vim/State/Marks.js @@ -0,0 +1,31 @@ +(function(){ + var ns = __namespace( "Components.Vim.State" ); + + /** @type {System.Debug} */ + var debug = __import( "System.Debug" ); + + var Keys = "'ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy\"[]^.<>"; + + var Marks = function() + { + this.__marks = {}; + }; + + Marks.prototype.set = function( t, line, col ) + { + if( Keys.indexOf( t ) == -1 ) return false; + + this.__marks[ t ] = [ line, col ]; + return true; + }; + + Marks.prototype.get = function( t ) + { + return this.__marks[ t ]; + }; + + __readOnly( Marks, "Keys", function() { return Keys; } ); + + ns[ NS_EXPORT ]( EX_CLASS, "Marks", Marks ); + +})(); diff --git a/botanjs/src/Components/Vim/VimArea.js b/botanjs/src/Components/Vim/VimArea.js index aad55ee..8986ce6 100644 --- a/botanjs/src/Components/Vim/VimArea.js +++ b/botanjs/src/Components/Vim/VimArea.js @@ -14,6 +14,8 @@ /** @type {Components.Vim.State.Registers} */ var Registers = __import( "Components.Vim.State.Registers" ); + /** @type {Components.Vim.State.Marks} */ + var Marks = __import( "Components.Vim.State.Marks" ); /** @type {Components.Vim.Syntax.Analyzer} */ var SyntaxAnalyzer = __import( "Components.Vim.Syntax.Analyzer" ); @@ -58,10 +60,10 @@ throw new Error( "This element is not compatible for VimArea" ); } - for( var i in Insts ) + for( var i = 0; i < InstIndex; i ++ ) { var inst = Insts[ i ]; - if( inst.stage.element == element ) + if( inst && inst.stage.element == element ) { debug.Info( "Instance exists" ); return inst; @@ -243,6 +245,7 @@ this.statusFeeder = sfeeder; this.statusBar = statusBar; this.registers = new Registers(); + this.marks = new Marks(); this.__cursor = cfeeder.cursor; @@ -387,7 +390,12 @@ __readOnly( VimArea, "Instances", function() { var clone = []; - for( var i in Insts ) clone.push( Insts[ i ] ); + + for( var i = 0; i < InstIndex; i ++ ) + { + if( Insts[ i ] ) clone.push( Insts[ i ] ); + } + return clone; } ); diff --git a/botanjs/src/externs/Components.Vim.Cursor.js b/botanjs/src/externs/Components.Vim.Cursor.js index 2b60b30..634cd47 100644 --- a/botanjs/src/externs/Components.Vim.Cursor.js +++ b/botanjs/src/externs/Components.Vim.Cursor.js @@ -13,6 +13,8 @@ Components.Vim.Cursor.rec; /** @type Function */ Components.Vim.Cursor.moveTo; /** @type Function */ +Components.Vim.Cursor.gotoLine; +/** @type Function */ Components.Vim.Cursor.moveX; /** @type Function */ Components.Vim.Cursor.moveY; diff --git a/botanjs/src/externs/Components.Vim.LineFeeder.js b/botanjs/src/externs/Components.Vim.LineFeeder.js index eb500db..5edec59 100644 --- a/botanjs/src/externs/Components.Vim.LineFeeder.js +++ b/botanjs/src/externs/Components.Vim.LineFeeder.js @@ -43,6 +43,8 @@ Components.Vim.LineFeeder.linesOccupied; /** @type String */ Components.Vim.LineFeeder.docPos; /** @type String */ +Components.Vim.LineFeeder.line; +/** @type String */ Components.Vim.LineFeeder.lineStat; /** @type {String} */ Components.Vim.LineFeeder.content; diff --git a/botanjs/src/externs/Components.Vim.State.Marks.js b/botanjs/src/externs/Components.Vim.State.Marks.js new file mode 100644 index 0000000..99a4ade --- /dev/null +++ b/botanjs/src/externs/Components.Vim.State.Marks.js @@ -0,0 +1,10 @@ +/** @constructor */ +Components.Vim.State.Marks = function(){}; + +/** @type Function */ +Components.Vim.State.Marks.set; +/** @type Function */ +Components.Vim.State.Marks.get; + +/** @type String */ +Components.Vim.State.Marks.Keys; diff --git a/botanjs/src/externs/Components.Vim.VimArea.js b/botanjs/src/externs/Components.Vim.VimArea.js index 756c6c3..a2286d1 100644 --- a/botanjs/src/externs/Components.Vim.VimArea.js +++ b/botanjs/src/externs/Components.Vim.VimArea.js @@ -12,6 +12,11 @@ Components.Vim.VimArea.statusFeeder; /** @type {Components.Vim.StatusBar} */ Components.Vim.VimArea.statusBar; +/** @type {Components.Vim.State.Registers} */ +Components.Vim.VimArea.registers; +/** @type {Components.Vim.State.Marks} */ +Components.Vim.VimArea.marks; + /** @type Function */ Components.Vim.VimArea.demo; /** @type Function */