
Reference.pudu
Pudu64 lines3.2 KB
1/** @App.Tools.Reference.Handler — API search and module reference tools */2module PuduLangMcp.App.Tools.Reference34import Std.List as List5import Std.Option as Option6import PuduLangMcp.App.Context as Context7import PuduLangMcp.Constants.Server as Server8import PuduLangMcp.Domain.Catalog.Arguments as Arguments9import PuduLangMcp.Domain.Reference.Entry as Entry10import PuduLangMcp.Errors.ToolError as ToolError11import PuduLangMcp.Services.Reference as Reference12import PuduLangMcp.Utils.TextBounds as TextBounds131415const SHAPE_MARK: Str = "->"161718const SUGGESTIONS: Int = 8192021export fn search(context: &Context.Context, args: &Arguments.Args) -> Result[Str, ToolError.ToolFailure] {22 let query = Option.unwrapOr(Arguments.text(args, "query"), "").trim()23 let limit = Arguments.integerOr(args, "limit", Server.DEFAULT_SEARCH_LIMIT)24 if query.contains(SHAPE_MARK) { return shapeSearch(context, query) }25 let entries = Context.entries(context) ?26 let found = Entry.search(&entries, query, limit)27 if found.isEmpty() { return Ok("No declaration matches '" + query + "'.") }28 Ok(TextBounds.bounded(found.map(|held: Entry.Found| Entry.render(&held.entry)).join("\n\n"), Server.DOC_CHARS))29}303132export fn moduleTool(context: &Context.Context, args: &Arguments.Args) -> Result[Str, ToolError.ToolFailure] {33 moduleText(context, Option.unwrapOr(Arguments.text(args, "module"), "").trim())34}353637export fn moduleText(context: &Context.Context, moduleName: Str) -> Result[Str, ToolError.ToolFailure] {38 let file = match Reference.fileOf(&context.moduleFiles, moduleName) {39 case Some(found) => found40 case None => {41 let wanted = moduleName.toLower()42 let near = List.take(&context.moduleFiles.filter(|held: Reference.ModuleFile| held.moduleName.toLower().contains(wanted)), SUGGESTIONS)43 let hint = if near.isEmpty() { "" } else { " (did you mean: " + near.map(|held: Reference.ModuleFile| held.moduleName).join(", ") + ")" }44 return Err(ToolError.NotFound("Module '" + moduleName + "'" + hint))45 }46 }47 let entries = Reference.moduleEntries(&context.toolchain, &file) ?48 Ok(TextBounds.bounded(Entry.renderModule(&entries, moduleName), Server.DOC_CHARS))49}505152fn shapeSearch(context: &Context.Context, query: Str) -> Result[Str, ToolError.ToolFailure] {53 if context.toolchain.compiler == None { return Err(ToolError.ToolchainMissing) }54 let arguments = ["search", query].concat(context.moduleFiles.map(|held: Reference.ModuleFile| held.path))55 match context.toolchain.run(arguments, "", "", Server.REFERENCE_TIMEOUT_MS, Server.OUTPUT_CAP_BYTES) {56 case Ok(done) => {57 if done.timedOut { return Err(ToolError.TimedOut("pudu search", Server.REFERENCE_TIMEOUT_MS)) }58 let said = done.output.trim()59 Ok(if said.isEmpty() { "No declaration has the shape '" + query + "'." } else { TextBounds.bounded(said, Server.DOC_CHARS) })60 }61 case Err(problem) => Err(ToolError.CommandFailed(problem))62 }63}64