How to move the caret to the preceeding/following tag

Brent Hartwig shares an interesting exercise, using regular expressions but (almost) no oid functions. Last Updated: 2006-07-31

Remember the days before oid functions?

From your posting, I understood you wanted to move either after the previous start tag or before the previous end tag, which ever comes first. And, the caret must be on the same line as that tag. The code below does this and includes an implementation of the same location logic but in the opposite direction. The main/public functions are the last two: MoveToPreviousTag and MoveToNextTag.

Example: Given the XML snippet where Points C through I are all on the same line...

 Some textSome more text 

...starting at point A, MoveToNextTag would stop at points B, D, F, H and J. Starting at point K, MoveToPreviousTag would stop at points J, H, F, D and B. Notice that this code, running in either direction, will not stop at points A, C, E, G, I or K. The only logic to "skip" points is if the caret starts at a point; therefore, if you're starting from either point E or G, points D, F or H will not be skipped. Further, if point F's tag was removed and the caret is somewhere between points D and H, the code will not skip those points. This is by design but may or may not be desired.

package MoveCaret; function LookingAtStartTag( directly = 1 ) {  local regex = ""; if ( !directly ) {     regex .= ".*"; }  regex .= "]*>"; return looking_at( regex ); } function LookingAtEndTag( directly = 1 ) {  local regex = ""; if ( !directly ) {     regex .= ".*"; }  regex .= "]+>"; # Added condition that we're not looking at a start tag; otherwise, this # function returns true when caret precedes start and end tag pair without # content; i.e., [caret]. return (!LookingAtStartTag && looking_at( regex )); } # function MoveToTag( next = 1, beforeTag = 0 ) {  local cmd = 'caret 0,'; if ( !next ) {     cmd .= '-'; }  cmd .= '"]+>"'; if ( next && beforeTag ) {     cmd .= '-1'; }  cmd .= ' -e -t -nowrapscan'; return (execute(cmd) == 0); } function MoveToPreviousTag {  local doc = current_doc; local oFirst = oid_first( doc ); if ( oid_valid( oFirst ) ) {     local pos = oid_caret_offset( oFirst ); if ( MoveToTag( 0 ) ) {        # If we just moved in front of the start tag we were immediately # after, move again. if ( LookingAtStartTag && ( oid_caret_offset( oFirst ) == \ ( pos - 1 ) ) ) {           if ( !MoveToTag( 0 ) ) { return }; }        # If we're looking at a start tag, move after it. if ( LookingAtStartTag ) {           forward_char( 1 ); }     }   } } function MoveToNextTag {  # If looking at an end tag, move after it. if ( LookingAtEndTag ) {     forward_char( 1 ); }  # Move to next tag. If end tag comes before start tag, submit true for # "beforeTag" parameter indicating we want the caret left before the # end tag. MoveToTag( 1, LookingAtEndTag( 0 ) ); }
 * 1) Returns boolean indicating if caret of current doc is in front of a start
 * 2) tag. If the "directly" parameter is true, this function will only return true
 * 3) when the caret is immediately in front of a start tag; when false, a start
 * 4) tag must only come before an end tag.
 * 1) Returns boolean indicating if caret of current doc is in front of an end tag.
 * 2) If the "directly" parameter is true, this function will only return true when
 * 3) the caret is immediately in front of an end tag; when false, an end tag must
 * 4) only come before a start tag.
 * 1) Moves the caret of the current doc before or after a start or end tag.
 * 1) Parameters:
 * 2)  next - If true, caret to move forward; else, move backward.
 * 3)  beforeTag - Only used if next is true. When both are true, caret is to move
 * 4)    in front of (end) tag. This function doesn't know if moving after a start
 * 5)    or end tag. Determine this before calling and set this parameter as
 * 6)    appropriate.
 * 1) Moves the caret of the current doc immediately after the preceding start tag
 * 2) or immediate in front of the preceding end tag, which ever comes first.
 * 1) Moves the caret of the current doc immediate after the following start tag
 * 2) or immediate in front of the following end tag, which ever comes first.