import * as vscode from 'vscode' ; import { getDeepestNode , findNextWord , findPrevWord , getHtmlNode } from './util' ; import { HtmlNode } from 'EmmetNode' ; import { isNumber } from 'util' ; export function nextItemHTML ( selectionStart , selectionEnd , editor , rootNode ) { let currentNode = getHtmlNode ( editor . document , rootNode , selectionEnd , false ) ; let nextNode = undefined ; if ( ! currentNode ) { return ; } if ( currentNode . type !== 'comment' ) { if ( selectionEnd . isBefore ( currentNode . open . start . translate ( 0 , currentNode . name . length ) ) ) { return getSelectionFromNode ( currentNode ) ; } if ( selectionEnd . isBefore ( currentNode . open . end ) ) { let attrSelection = getNextAttribute ( selectionStart , selectionEnd , currentNode ) ; if ( attrSelection ) { return attrSelection ; } } nextNode = currentNode . firstChild ; while ( nextNode && ( selectionEnd . isAfterOrEqual ( nextNode . end ) || nextNode . type === 'comment' ) ) { nextNode = nextNode . nextSibling ; } } while ( ! nextNode && currentNode ) { if ( currentNode . nextSibling ) { if ( currentNode . nextSibling . type !== 'comment' ) { nextNode = currentNode . nextSibling ; } else { currentNode = currentNode . nextSibling ; } } else { currentNode = currentNode . parent ; } } return nextNode && getSelectionFromNode ( nextNode ) ; } export function prevItemHTML ( selectionStart , selectionEnd , editor , rootNode ) { let currentNode = getHtmlNode ( editor . document , rootNode , selectionStart , false ) ; let prevNode = undefined ; if ( ! currentNode ) { return ; } if ( currentNode . type !== 'comment' && selectionStart . translate ( 0 , - 1 ) . isAfter ( currentNode . open . start ) ) { if ( selectionStart . isBefore ( currentNode . open . end ) || ! currentNode . firstChild || selectionEnd . isBeforeOrEqual ( currentNode . firstChild . start ) ) { prevNode = currentNode ; } else { prevNode = currentNode . firstChild ; let oldOption = undefined ; while ( prevNode . nextSibling && selectionStart . isAfterOrEqual ( prevNode . nextSibling . end ) ) { if ( prevNode && prevNode . type !== 'comment' ) { oldOption = prevNode ; } prevNode = prevNode . nextSibling ; } prevNode = < HtmlNode > getDeepestNode ( ( prevNode && prevNode . type !== 'comment' ) ? prevNode : oldOption ) ; } } while ( ! prevNode && currentNode ) { if ( currentNode . previousSibling ) { if ( currentNode . previousSibling . type !== 'comment' ) { prevNode = < HtmlNode > getDeepestNode ( currentNode . previousSibling ) ; } else { currentNode = currentNode . previousSibling ; } } else { prevNode = currentNode . parent ; } } if ( ! prevNode ) { return undefined ; } let attrSelection = getPrevAttribute ( selectionStart , selectionEnd , prevNode ) ; return attrSelection ? attrSelection : getSelectionFromNode ( prevNode ) ; } function getSelectionFromNode ( node ) { if ( node && node . open ) { let selectionStart = ( < vscode . Position > node . open . start ) . translate ( 0 , 1 ) ; let selectionEnd = selectionStart . translate ( 0 , node . name . length ) ; return new vscode . Selection ( selectionStart , selectionEnd ) ; } return undefined ; } function getNextAttribute ( selectionStart , selectionEnd , node ) { if ( ! node . attributes || node . attributes . length === 0 || node . type === 'comment' ) { return ; } for ( const attr of node . attributes ) { if ( selectionEnd . isBefore ( attr . start ) ) { return new vscode . Selection ( attr . start , attr . end ) ; } if ( ! attr . value || ( < vscode . Position > attr . value . start ) . isEqual ( attr . value . end ) ) { continue ; } if ( ( selectionStart . isEqual ( attr . start ) && selectionEnd . isEqual ( attr . end ) ) || selectionEnd . isBefore ( attr . value . start ) ) { return new vscode . Selection ( attr . value . start , attr . value . end ) ; } if ( attr . value . toString ( ) . indexOf ( ' ' ) === - 1 ) { continue ; } let pos = undefined ; if ( selectionStart . isEqual ( attr . value . start ) && selectionEnd . isEqual ( attr . value . end ) ) { pos = - 1 ; } if ( pos === undefined && selectionEnd . isBefore ( attr . end ) ) { pos = selectionEnd . character - attr . value . start . character - 1 ; } if ( pos !== undefined ) { let [ newSelectionStartOffset , newSelectionEndOffset ] = findNextWord ( attr . value . toString ( ) , pos ) ; if ( ! isNumber ( newSelectionStartOffset ) || ! isNumber ( newSelectionEndOffset ) ) { return ; } if ( newSelectionStartOffset >= 0 && newSelectionEndOffset >= 0 ) { const newSelectionStart = ( < vscode . Position > attr . value . start ) . translate ( 0 , newSelectionStartOffset ) ; const newSelectionEnd = ( < vscode . Position > attr . value . start ) . translate ( 0 , newSelectionEndOffset ) ; return new vscode . Selection ( newSelectionStart , newSelectionEnd ) ; } } } return ; } function getPrevAttribute ( selectionStart , selectionEnd , node ) { if ( ! node . attributes || node . attributes . length === 0 || node . type === 'comment' ) { return ; } for ( let i = node . attributes . length - 1 ; i >= 0 ; i -- ) { let attr = node . attributes [ i ] ; if ( selectionStart . isBeforeOrEqual ( attr . start ) ) { continue ; } if ( ! attr . value || ( < vscode . Position > attr . value . start ) . isEqual ( attr . value . end ) || selectionStart . isBefore ( attr . value . start ) ) { return new vscode . Selection ( attr . start , attr . end ) ; } if ( selectionStart . isEqual ( attr . value . start ) ) { if ( selectionEnd . isAfterOrEqual ( attr . value . end ) ) { return new vscode . Selection ( attr . start , attr . end ) ; } return new vscode . Selection ( attr . value . start , attr . value . end ) ; } let pos = selectionStart . isAfter ( attr . value . end ) ? attr . value . toString ( ) . length : selectionStart . character - attr . value . start . character ; let [ newSelectionStartOffset , newSelectionEndOffset ] = findPrevWord ( attr . value . toString ( ) , pos ) ; if ( ! isNumber ( newSelectionStartOffset ) || ! isNumber ( newSelectionEndOffset ) ) { return ; } if ( newSelectionStartOffset >= 0 && newSelectionEndOffset >= 0 ) { const newSelectionStart = ( < vscode . Position > attr . value . start ) . translate ( 0 , newSelectionStartOffset ) ; const newSelectionEnd = ( < vscode . Position > attr . value . start ) . translate ( 0 , newSelectionEndOffset ) ; return new vscode . Selection ( newSelectionStart , newSelectionEnd ) ; } } return ; }