@@ -14,6 +14,7 @@ import {
1414 BpfConditionalJmpInstruction ,
1515 BpfTargetJmpInstruction ,
1616 InstructionLine ,
17+ getCLineId ,
1718} from "./parser" ;
1819import {
1920 BpfMemSlotMap ,
@@ -821,6 +822,98 @@ export function SelectedLineHint({
821822 ) ;
822823}
823824
825+ function CSourcePastePopup ( {
826+ verifierLogState,
827+ fileName,
828+ onHideCSourcePaste,
829+ addPastedCSourceFile,
830+ } : {
831+ verifierLogState : VerifierLogState ;
832+ fileName : string ;
833+ onHideCSourcePaste : ( ) => void ;
834+ addPastedCSourceFile : ( fileName : string , pastedLines : string [ ] ) => void ;
835+ } ) {
836+ const [ pastedContent , setPastedContent ] = useState ( "" ) ;
837+ const [ mismatchError , setMismatcError ] = useState ( false ) ;
838+
839+ const handleChange = useCallback (
840+ ( event : ChangeEvent < HTMLTextAreaElement > ) => {
841+ setMismatcError ( false ) ;
842+ const pastedText = event . target . value ;
843+ setPastedContent ( pastedText ) ;
844+ const pastedLines : string [ ] = pastedText . split ( "\n" ) ;
845+ for ( const [ file ] of verifierLogState . cSourceMap . fileRange ) {
846+ if ( file !== fileName ) {
847+ continue ;
848+ }
849+ pastedLines . some ( ( lineText , i ) => {
850+ const lineNum = i + 1 ;
851+ const sourceId = getCLineId ( file , lineNum ) ;
852+ const sourceLine =
853+ verifierLogState . cSourceMap . cSourceLines . get ( sourceId ) ;
854+ if ( sourceLine && ! sourceLine . ignore ) {
855+ if ( ! lineText . includes ( sourceLine . content ) ) {
856+ setMismatcError ( true ) ;
857+ return true ;
858+ }
859+ }
860+ return false ;
861+ } ) ;
862+ }
863+ } ,
864+ [ ] ,
865+ ) ;
866+
867+ const handleConfirm = useCallback ( ( ) => {
868+ addPastedCSourceFile ( fileName , pastedContent . split ( "\n" ) ) ;
869+ onHideCSourcePaste ( ) ;
870+ } , [ pastedContent ] ) ;
871+
872+ const handleClear = useCallback ( ( ) => {
873+ setPastedContent ( "" ) ;
874+ setMismatcError ( false ) ;
875+ } , [ ] ) ;
876+
877+ const onContentClick = useCallback (
878+ ( event : React . MouseEvent < HTMLDivElement > ) => {
879+ event . stopPropagation ( ) ;
880+ } ,
881+ [ ] ,
882+ ) ;
883+
884+ return (
885+ < div onClick = { onHideCSourcePaste } className = "c-source-popup-overlay" >
886+ < div onClick = { onContentClick } className = "c-source-popup-content" >
887+ < h3 > Paste contents of { fileName } </ h3 >
888+ < textarea
889+ className = "c-source-textarea"
890+ value = { pastedContent }
891+ onChange = { handleChange }
892+ placeholder = "Paste the entire file contents"
893+ />
894+ { mismatchError && (
895+ < div className = "c-source-popup-error" >
896+ Pasted content does not match the verifier log.
897+ < br />
898+ Make sure the entire file contents are pasted and the line numbers
899+ match
900+ </ div >
901+ ) }
902+ < button
903+ className = "c-source-button"
904+ onClick = { handleConfirm }
905+ disabled = { mismatchError || pastedContent === "" }
906+ >
907+ Apply
908+ </ button >
909+ < button className = "c-source-button" onClick = { handleClear } >
910+ Clear
911+ </ button >
912+ </ div >
913+ </ div >
914+ ) ;
915+ }
916+
824917function HideShowButton ( {
825918 isVisible,
826919 rightOpen,
@@ -1162,6 +1255,7 @@ type CSourceRowProps = {
11621255 cLines : CSourceRow [ ] ;
11631256 dependencyCLines : Set < string > ;
11641257 selectedCLine : string ;
1258+ onShowCSourcePaste : ( fileName : string ) => void ;
11651259} ;
11661260
11671261function CSourceRowHeight ( index : number , { cLines } : CSourceRowProps ) {
@@ -1181,17 +1275,29 @@ const CSourceRowComponent = ({
11811275 cLines,
11821276 dependencyCLines,
11831277 selectedCLine,
1278+ onShowCSourcePaste,
11841279} : RowComponentProps < CSourceRowProps > ) => {
11851280 const item = cLines [ index ] ;
11861281
1282+ const onFilePasteClick = ( ) => {
1283+ onShowCSourcePaste ( item . file ) ;
1284+ } ;
1285+
11871286 if ( item . type == "file_name" ) {
11881287 const fileNameStyle = { ...style } ;
11891288 if ( index === 0 ) {
11901289 fileNameStyle [ "borderTop" ] = "0px" ;
11911290 }
11921291 return (
1193- < div className = "filename-header" style = { fileNameStyle } >
1194- { item . file }
1292+ < div
1293+ onClick = { onFilePasteClick }
1294+ className = "filename-header"
1295+ style = { fileNameStyle }
1296+ >
1297+ { item . file } { "\u{1F4CB}" }
1298+ < div className = "filename-tooltip" >
1299+ Click to replace lines with actual source code
1300+ </ div >
11951301 </ div >
11961302 ) ;
11971303 }
@@ -1241,6 +1347,7 @@ function CSourceLinesRaw({
12411347 handleFullLogToggle,
12421348 handleCLinesClick,
12431349 onCRowsRendered,
1350+ onShowCSourcePaste,
12441351} : {
12451352 showFullLog : boolean ;
12461353 selectedState : LogLineState ;
@@ -1251,6 +1358,7 @@ function CSourceLinesRaw({
12511358 handleFullLogToggle : ( ) => void ;
12521359 handleCLinesClick : ( event : React . MouseEvent < HTMLDivElement > ) => void ;
12531360 onCRowsRendered : ( start : number , end : number ) => void ;
1361+ onShowCSourcePaste : ( fileName : string ) => void ;
12541362} ) {
12551363 const buttonId = "csource-toggle" ;
12561364
@@ -1358,6 +1466,7 @@ function CSourceLinesRaw({
13581466 cLines : visualLogState . cLines ,
13591467 dependencyCLines,
13601468 selectedCLine,
1469+ onShowCSourcePaste,
13611470 } }
13621471 />
13631472 </ div >
@@ -1375,6 +1484,7 @@ export function MainContent({
13751484 handleLogLinesOut,
13761485 handleFullLogToggle,
13771486 testListHeight,
1487+ addPastedCSourceFile,
13781488} : {
13791489 visualLogState : VisualLogState ;
13801490 selectedState : LogLineState ;
@@ -1383,6 +1493,7 @@ export function MainContent({
13831493 handleLogLinesOut : ( event : React . MouseEvent < HTMLDivElement > ) => void ;
13841494 handleFullLogToggle : ( ) => void ;
13851495 testListHeight : number | undefined ;
1496+ addPastedCSourceFile : ( fileName : string , pastedLines : string [ ] ) => void ;
13861497} ) {
13871498 const logListRef = useListRef ( null ) ;
13881499 const cListRef = useListRef ( null ) ;
@@ -1410,6 +1521,19 @@ export function MainContent({
14101521 visualLogEnd : number ;
14111522 } > ( { visualLogStart : 0 , visualLogEnd : 0 } ) ;
14121523
1524+ const [ cSourcePaste , setCSourcePaste ] = useState < {
1525+ show : boolean ;
1526+ fileName : string ;
1527+ } > ( { show : false , fileName : "" } ) ;
1528+
1529+ const onShowCSourcePaste = useCallback ( ( fileName : string ) => {
1530+ setCSourcePaste ( { show : true , fileName } ) ;
1531+ } , [ ] ) ;
1532+
1533+ const onHideCSourcePaste = useCallback ( ( ) => {
1534+ setCSourcePaste ( { show : false , fileName : "" } ) ;
1535+ } , [ ] ) ;
1536+
14131537 const onCRowsRendered = useCallback ( ( start : number , end : number ) => {
14141538 setVisualCIndexRange ( { visualLogStart : start , visualLogEnd : end } ) ;
14151539 } , [ ] ) ;
@@ -1484,6 +1608,10 @@ export function MainContent({
14841608
14851609 useEffect ( ( ) => {
14861610 const handleKeyDown = ( e : KeyboardEvent ) => {
1611+ if ( cSourcePaste . show ) {
1612+ return ;
1613+ }
1614+
14871615 let delta = 0 ;
14881616 let areCLinesInFocus = selectedState . cLine !== "" ;
14891617 let min = 0 ;
@@ -1931,6 +2059,7 @@ export function MainContent({
19312059 cListRef = { cListRef }
19322060 onCRowsRendered = { onCRowsRendered }
19332061 testListHeight = { testListHeight }
2062+ onShowCSourcePaste = { onShowCSourcePaste }
19342063 />
19352064 < div
19362065 id = "log-container"
@@ -1977,6 +2106,14 @@ export function MainContent({
19772106 handleStateCLineClick = { handleStateCLineClick }
19782107 handleStateRowClick = { handleStateRowClick }
19792108 />
2109+ { cSourcePaste . show && (
2110+ < CSourcePastePopup
2111+ verifierLogState = { verifierLogState }
2112+ onHideCSourcePaste = { onHideCSourcePaste }
2113+ fileName = { cSourcePaste . fileName }
2114+ addPastedCSourceFile = { addPastedCSourceFile }
2115+ />
2116+ ) }
19802117 </ div >
19812118 ) ;
19822119}
0 commit comments