|  | 
|  | 1 | +import { | 
|  | 2 | +    CancellationError, | 
|  | 3 | +    CancellationToken, | 
|  | 4 | +    CodeLens, | 
|  | 5 | +    CodeLensProvider, | 
|  | 6 | +    DocumentSymbol, | 
|  | 7 | +    Event, | 
|  | 8 | +    ProviderResult, | 
|  | 9 | +    SymbolKind, | 
|  | 10 | +    TextDocument, | 
|  | 11 | +    commands, | 
|  | 12 | +} from 'vscode'; | 
|  | 13 | +import { CMD_BUILD_AND_DEBUG_MAIN, CMD_BUILD_AND_RUN_MAIN } from './commands'; | 
|  | 14 | +import { getMains, getSymbols } from './helpers'; | 
|  | 15 | + | 
|  | 16 | +export class AdaCodeLensProvider implements CodeLensProvider { | 
|  | 17 | +    static readonly ENABLE_SPARK_CODELENS = false; | 
|  | 18 | + | 
|  | 19 | +    onDidChangeCodeLenses?: Event<void> | undefined; | 
|  | 20 | +    provideCodeLenses( | 
|  | 21 | +        document: TextDocument, | 
|  | 22 | +        token?: CancellationToken | 
|  | 23 | +    ): ProviderResult<CodeLens[]> { | 
|  | 24 | +        const symbols = commands.executeCommand<DocumentSymbol[]>( | 
|  | 25 | +            'vscode.executeDocumentSymbolProvider', | 
|  | 26 | +            document.uri | 
|  | 27 | +        ); | 
|  | 28 | + | 
|  | 29 | +        /** | 
|  | 30 | +         * For main procedures, provide Run and Debug CodeLenses. | 
|  | 31 | +         */ | 
|  | 32 | +        const res1 = getMains().then((mains) => { | 
|  | 33 | +            if (mains.some((m) => m == document.fileName)) { | 
|  | 34 | +                // It's a main file, so let's offer Run and Debug actions on the main subprogram | 
|  | 35 | +                return symbols.then((symbols) => { | 
|  | 36 | +                    const functions = symbols.filter((s) => s.kind == SymbolKind.Function); | 
|  | 37 | +                    if (functions.length > 0) { | 
|  | 38 | +                        /** | 
|  | 39 | +                         * We choose to provide the CodeLenses on the first | 
|  | 40 | +                         * subprogram of the file. It may be possible that the | 
|  | 41 | +                         * main subprogram is not the first one, but that's an | 
|  | 42 | +                         * unlikely scenario that we choose not to handle for | 
|  | 43 | +                         * the moment. | 
|  | 44 | +                         */ | 
|  | 45 | +                        return [ | 
|  | 46 | +                            new CodeLens(functions[0].range, { | 
|  | 47 | +                                command: CMD_BUILD_AND_RUN_MAIN, | 
|  | 48 | +                                title: '$(run) Run', | 
|  | 49 | +                                arguments: [document.uri], | 
|  | 50 | +                            }), | 
|  | 51 | +                            // TODO implement this command | 
|  | 52 | +                            new CodeLens(functions[0].range, { | 
|  | 53 | +                                command: CMD_BUILD_AND_DEBUG_MAIN, | 
|  | 54 | +                                title: '$(debug-alt-small) Debug', | 
|  | 55 | +                                arguments: [document.uri], | 
|  | 56 | +                            }), | 
|  | 57 | +                        ]; | 
|  | 58 | +                    } else { | 
|  | 59 | +                        return []; | 
|  | 60 | +                    } | 
|  | 61 | +                }); | 
|  | 62 | +            } else { | 
|  | 63 | +                return []; | 
|  | 64 | +            } | 
|  | 65 | +        }); | 
|  | 66 | + | 
|  | 67 | +        let res2; | 
|  | 68 | +        if (AdaCodeLensProvider.ENABLE_SPARK_CODELENS) { | 
|  | 69 | +            /** | 
|  | 70 | +             * This is tentative deactivated code in preparation of SPARK support. | 
|  | 71 | +             */ | 
|  | 72 | +            res2 = symbols.then<CodeLens[]>((symbols) => { | 
|  | 73 | +                const symbolKinds = [SymbolKind.Function]; | 
|  | 74 | +                const recurseInto = [SymbolKind.Module, SymbolKind.Package, SymbolKind.Function]; | 
|  | 75 | + | 
|  | 76 | +                // Create a named reduce function to implement a recursive visit of symbols | 
|  | 77 | +                const functions = getSymbols(symbols, symbolKinds, recurseInto, token); | 
|  | 78 | + | 
|  | 79 | +                return functions.map((f) => { | 
|  | 80 | +                    if (token?.isCancellationRequested) { | 
|  | 81 | +                        throw new CancellationError(); | 
|  | 82 | +                    } | 
|  | 83 | +                    // TODO make SPARK codelenses conditional to the availability of SPARK on PATH | 
|  | 84 | +                    return new CodeLens(f.range, { | 
|  | 85 | +                        title: '$(play-circle) Prove', | 
|  | 86 | +                        command: 'TODO', | 
|  | 87 | +                    }); | 
|  | 88 | +                }); | 
|  | 89 | +            }); | 
|  | 90 | +        } else { | 
|  | 91 | +            res2 = Promise.resolve([]); | 
|  | 92 | +        } | 
|  | 93 | + | 
|  | 94 | +        return Promise.all([res1, res2]).then((results) => { | 
|  | 95 | +            return results[0].concat(results[1]); | 
|  | 96 | +        }); | 
|  | 97 | +    } | 
|  | 98 | +    // eslint-disable-next-line @typescript-eslint/no-unused-vars | 
|  | 99 | +    resolveCodeLens?(codeLens: CodeLens, _token: CancellationToken): ProviderResult<CodeLens> { | 
|  | 100 | +        if (codeLens.command) { | 
|  | 101 | +            return codeLens; | 
|  | 102 | +        } else { | 
|  | 103 | +            throw new Error(`Cannot resolve CodeLens`); | 
|  | 104 | +        } | 
|  | 105 | +    } | 
|  | 106 | +} | 
0 commit comments