public void makeAdjustments(Consumer<String> logger, String inoFile, String projectName, List<String> callbacks) throws IOException {

        this.logger = logger;
        changed = false;

        Path source = Paths.get(inoFile);
        if (!Files.exists(source)) {
            logger.accept("No existing infoFile, generating an empty one");
            Files.write(source, ArduinoSketchFileAdjuster.EMPTY_SKETCH.getBytes());
        }

        boolean needsInclude = true;
        boolean needsTaskMgr = true;
        boolean needsSetup = true;
        List<String> callbacksDefined = new ArrayList<>();

        for(String line : Files.lines(source).collect(Collectors.toList())) {
            if(line.contains("#include") && line.contains(projectName + "_menu.h")) {
                logger.accept("found include in INO");
                needsInclude = false;
            }
            else if(line.contains("taskManager.runLoop()")) {
                logger.accept("found runLoop in INO");
                needsTaskMgr = false;
            }
            else if(line.contains("setupMenu(")) {
                logger.accept("found setup in INO");
                needsSetup = false;
            }
            else if(line.contains("CALLBACK_FUNCTION")) {
                Matcher fnMatch = FUNCTION_PATTERN.matcher(line);
                if(fnMatch.matches()) {
                    logger.accept("found callback for " + fnMatch.group(1));
                    callbacksDefined.add(fnMatch.group(1));
                }
            }
        }

        ArrayList<String> lines = new ArrayList<>(Files.readAllLines(source));
        if(needsInclude) addIncludeToTopOfFile(lines, projectName);
        if(needsSetup) addSetupCode(lines, SETUP_PATTERN, "    setupMenu();");
        if(needsTaskMgr) addSetupCode(lines, LOOP_PATTERN, "    taskManager.runLoop();");
        List<String> callbacksToMake = new ArrayList<>(callbacks);
        callbacksToMake.removeAll(callbacksDefined);

        makeNewCallbacks(lines, callbacksToMake);

        if(changed) {
            logger.accept("INO Previously existed, backup existing file");
            Files.copy(source, Paths.get(source.toString() + ".backup"), REPLACE_EXISTING);

            logger.accept("Writing out changes to INO sketch file");
            Files.write(Paths.get(inoFile), lines);
        }
        else {
            logger.accept("No changes to the INO file, not writing out");
        }
    }
public void makeAdjustments ( Consumer < String > logger , String inoFile , String projectName , List < String > callbacks ) throws IOException { this . logger = logger ; changed = false ; Path source = Paths . get ( inoFile ) ; if ( ! Files . exists ( source ) ) { logger . accept ( "No existing infoFile, generating an empty one" ) ; Files . write ( source , ArduinoSketchFileAdjuster . EMPTY_SKETCH . getBytes ( ) ) ; } boolean needsInclude = true ; boolean needsTaskMgr = true ; boolean needsSetup = true ; List < String > callbacksDefined = new ArrayList < > ( ) ; for ( String line : Files . lines ( source ) . collect ( Collectors . toList ( ) ) ) { if ( line . contains ( "#include" ) && line . contains ( projectName + "_menu.h" ) ) { logger . accept ( "found include in INO" ) ; needsInclude = false ; } else if ( line . contains ( "taskManager.runLoop()" ) ) { logger . accept ( "found runLoop in INO" ) ; needsTaskMgr = false ; } else if ( line . contains ( "setupMenu(" ) ) { logger . accept ( "found setup in INO" ) ; needsSetup = false ; } else if ( line . contains ( "CALLBACK_FUNCTION" ) ) { Matcher fnMatch = FUNCTION_PATTERN . matcher ( line ) ; if ( fnMatch . matches ( ) ) { logger . accept ( "found callback for " + fnMatch . group ( 1 ) ) ; callbacksDefined . add ( fnMatch . group ( 1 ) ) ; } } } ArrayList < String > lines = new ArrayList < > ( Files . readAllLines ( source ) ) ; if ( needsInclude ) addIncludeToTopOfFile ( lines , projectName ) ; if ( needsSetup ) addSetupCode ( lines , SETUP_PATTERN , "    setupMenu();" ) ; if ( needsTaskMgr ) addSetupCode ( lines , LOOP_PATTERN , "    taskManager.runLoop();" ) ; List < String > callbacksToMake = new ArrayList < > ( callbacks ) ; callbacksToMake . removeAll ( callbacksDefined ) ; makeNewCallbacks ( lines , callbacksToMake ) ; if ( changed ) { logger . accept ( "INO Previously existed, backup existing file" ) ; Files . copy ( source , Paths . get ( source . toString ( ) + ".backup" ) , REPLACE_EXISTING ) ; logger . accept ( "Writing out changes to INO sketch file" ) ; Files . write ( Paths . get ( inoFile ) , lines ) ; } else { logger . accept ( "No changes to the INO file, not writing out" ) ; } }
Is able to update and round trip an ino file for the items that tcMenu needs.

Not thread safe, should be created for each run.
@param logger a consumer that handles UI logging
@param inoFile the file to be modified
@param projectName the project name
@param callbacks the list of callbacks.
@throws IOException in the event of an error