Issue Provider Not Putting Issues in the UI

I have developed a very simple Issue extension with main.js as follows:


exports.activate = function() {
    
}

exports.deactivate = function() {
    // Clean up state before the extension is deactivated
}


class IssuesProvider {
    provideIssues(editor) {
        const options = {
            args: ["rubocop", '--disable-pending-cops', '-fj', editor.document.path]
        };
        let rubocop = new Process("/usr/bin/env", options);
        let rawIssues = []
        let issues = [];

        rubocop.onStdout((line) => { rawIssues.push(line); });
        rubocop.onStderr((line) => { console.warn(`Rubocop ERROR: ${line}`); });
        rubocop.onDidExit((message) => {
            const allIssues = JSON.parse(rawIssues)['files'][0]['offenses'];
            allIssues.forEach((offense) => {
                console.log(`Rubocop Offnese: ${offense.message}`)
                let issue = new Issue();
                issue.message = offense['message']
                issue.code = offense['cop_name']
                issue.severity = IssueSeverity.Error;
                issue.column = offense["location"]["start_column"]
                // issue.endColumn = offense["location"]["end_column"]
                issue.line = offense["location"]["start_line"]
                // issue.endLine = offense["location"]["end_line"]
                issues.push(issue);
            })
            
            console.info(`Rubocop found ${issues.length} issue(s)`);
            return issues;
        });
        rubocop.start();
    }
}

nova.assistants.registerIssueAssistant("ruby", new IssuesProvider(), {event: "onChange"});

The console can receive the issues without issue, but nothing is appearing in the Nova user interface with the issue information. Given this mostly folllows the stock example provided when I start creating an Issue extension, I am a bit confused.

Your issue is that you never actually return anything from your provideIssues() function: the return issues line just returns the issues array from the onDidExit() callback. Because a Process launched via Nova’s API runs asynchronously, your issue provider function has long returned when the process exits, and because JS function expressions, unlike in Ruby, evaluate to undefined in the absence of an explicit return statement, Nova dutifully (and quite correctly) displays nothing.

The solution is to wrap your Process invocation in a Promise you resolve() in the callback and make your provideIssues() function async, thus enabling you to await the process and to actually return a value*. I have a utility function for running processes asynchronously here; feel free to use it for inspiration or to crib it wholesale.

* EDIT: if you don’t plan on adding anything significant to your function, like, say, error handling, just returning the Promise from it will work, too.

4 Likes

Thanks Martin for that helpful comment. It was not clear to me that Process runs asynchronously, but it does make sense that it would. Using your feedback I was able to finish and contribute my extension: https://extensions.panic.com/extensions/zagaja/zagaja.Rubocop/.

1 Like