import ts from 'typescript' ; import { Position , Range , SelectionRange } from 'vscode-languageserver' ; import { Document , mapSelectionRangeToParent } from '../../../lib/documents' ; import { SelectionRangeProvider } from '../../interfaces' ; import { SvelteSnapshotFragment } from '../DocumentSnapshot' ; import { LSAndTSDocResolver } from '../LSAndTSDocResolver' ; import { convertRange } from '../utils' ; export class SelectionRangeProviderImpl implements SelectionRangeProvider { constructor ( private readonly lsAndTsDocResolver ) { } async getSelectionRange ( document , position ) { const { tsDoc , lang } = await this . lsAndTsDocResolver . getLSAndTSDoc ( document ) ; const fragment = await tsDoc . getFragment ( ) ; const tsSelectionRange = lang . getSmartSelectionRange ( tsDoc . filePath , fragment . offsetAt ( fragment . getGeneratedPosition ( position ) ) ) ; const selectionRange = this . toSelectionRange ( fragment , tsSelectionRange ) ; const mappedRange = mapSelectionRangeToParent ( fragment , selectionRange ) ; return this . filterOutUnmappedRange ( mappedRange ) ; } private toSelectionRange ( fragment , { textSpan , parent } ) { return { range : convertRange ( fragment , textSpan ) , parent : parent && this . toSelectionRange ( fragment , parent ) } ; } private filterOutUnmappedRange ( selectionRange ) { const flattened = this . flattenAndReverseSelectionRange ( selectionRange ) ; const filtered = flattened . filter ( ( range ) => range . start . line > 0 && range . end . line > 0 ) ; if ( ! filtered . length ) { return null ; } let result ; for ( const selectionRange of filtered ) { result = SelectionRange . create ( selectionRange , result ) ; } return result ?? null ; } /**
     *   flatten the selection range and its parent to an array in reverse order
     * so it's easier to filter out unmapped selection and create a new tree of
     * selection range
     */ private flattenAndReverseSelectionRange ( selectionRange ) { const result = [ ] ; let current = selectionRange ; while ( current . parent ) { result . unshift ( current . range ) ; current = current . parent ; } return result ; } }