import { DebugProtocol } from 'vscode-debugprotocol' ; import { Breakpoint } from 'vscode-debugadapter' ; import { Commands , CommandInterface } from './Commands' ; import { functionFromPath } from './Utils/fsutils' ; import { dirname } from 'path' ; type ConditionalBreakpoint = DebugProtocol . SourceBreakpoint ; export class Breakpoints { private static readonly BP_REGEX = /^\s*(?:ans =)?\s*((?:\d+\s*)+)$/ ; private static setUnconditional ( breakpoints , confirmedBreakpoints , fname , runtime , callback ) { let lines = '' ; breakpoints . forEach ( b => lines += `${ b . line } ` ) ; let i = 0 ; runtime . evaluate ( `dbstop ${ fname } ${ lines }` , ( output ) => { output . forEach ( line => { const match = line . match ( Breakpoints . BP_REGEX ) ; if ( match !== null && match . length === 2 ) { const lines = match [ 1 ] . split ( ' ' ) . filter ( ( val ) => val ) ; lines . forEach ( l => { const bp = breakpoints [ i ++ ] ; const idx = ( bp . column ? bp . column : 0 ) ; confirmedBreakpoints [ idx ] = new Breakpoint ( true , parseInt ( l ) ) ; } ) ; } } ) ; if ( i === breakpoints . length ) { callback ( confirmedBreakpoints ) ; } } ) ; } private static setConditional ( breakpoints , confirmedBreakpoints , fname , runtime , callback ) { let i = 0 ; breakpoints . forEach ( b => { const expression = `dbstop in ${ fname } at ${ b . line } if ${ b . condition }` ; runtime . evaluate ( expression , ( output ) => { output . forEach ( line => { const match = line . match ( Breakpoints . BP_REGEX ) ; if ( match !== null && match . length === 2 ) { const l = match [ 1 ] ; const bp = breakpoints [ i ++ ] ; const idx = ( bp . column ? bp . column : 0 ) ; confirmedBreakpoints [ idx ] = new Breakpoint ( true , parseInt ( l ) ) ; } } ) ; if ( i === breakpoints . length ) { callback ( confirmedBreakpoints ) ; } } ) ; } ) ; } private static set ( breakpoints , path , runtime , cb ) { const confirmed = new Array < Breakpoint > ( ) ; if ( breakpoints . length !== 0 ) { const conditional = new Array < ConditionalBreakpoint > ( ) ; const unconditional = new Array < ConditionalBreakpoint > ( ) ; breakpoints . forEach ( b => { b . column = confirmed . length ; confirmed . push ( new Breakpoint ( false , b . line ) ) ; if ( b . condition !== undefined && b . condition . length !== 0 ) { conditional . push ( b ) ; } else { unconditional . push ( b ) ; } } ) ; const fname = functionFromPath ( path ) ; if ( unconditional . length !== 0 ) { if ( conditional . length !== 0 ) { Breakpoints . setUnconditional ( unconditional , confirmed , fname , runtime , ( confirmed ) => { Breakpoints . setConditional ( conditional , confirmed , fname , runtime , cb ) ; } ) ; } else { Breakpoints . setUnconditional ( unconditional , confirmed , fname , runtime , cb ) ; } } else { Breakpoints . setConditional ( conditional , confirmed , fname , runtime , cb ) ; } } else { cb ( confirmed ) ; } } private static listBreakpointsIn ( path , runtime , callback ) { const fname = functionFromPath ( path ) ; const breakpointRegEx = new RegExp ( `^\\s*breakpoint[s]? in ${ fname }(?:>\\w+)*? at line[s]? ((?:\\d+ ?)+)$` ) ; let lines = '' ; runtime . evaluate ( `dbstatus ${ fname }` , ( output ) => { output . forEach ( line => { const match = line . match ( breakpointRegEx ) ; if ( match !== null && match . length === 2 ) { lines += match [ 1 ] ; } } ) ; callback ( lines . trim ( ) ) ; } ) ; } private static clearAllBreakpointsIn ( path , ci , callback ) { Breakpoints . listBreakpointsIn ( path , ci , ( lines ) => { const func = functionFromPath ( path ) ; ci . execute ( `dbclear ${ func } ${ lines }` ) ; callback ( ) ; } ) ; } public static replaceBreakpoints ( breakpoints , path , runtime , callback ) { Commands . pushd ( runtime , dirname ( path ) , ( ci , popd ) => { Breakpoints . clearAllBreakpointsIn ( path , ci , ( ) => { Breakpoints . set ( breakpoints , path , ci , ( confirmedBreakpoints ) => { popd ( ci ) ; callback ( confirmedBreakpoints ) ; } ) ; } ) ; } ) ; } }