MCPcopy Create free account
hub / github.com/cli/cli / renderInteractive

Function renderInteractive

pkg/cmd/skills/preview/preview.go:318–374  ·  view source on GitHub ↗

renderInteractive shows the file tree, then a picker to browse individual files.

(opts *PreviewOptions, cs *iostreams.ColorScheme, skill discovery.Skill,
	files []discovery.SkillFile, renderedSkillMD string, extraFiles []discovery.SkillFile,
	apiClient *api.Client, hostname, owner, repo string)

Source from the content-addressed store, hash-verified

316
317// renderInteractive shows the file tree, then a picker to browse individual files.
318func renderInteractive(opts *PreviewOptions, cs *iostreams.ColorScheme, skill discovery.Skill,
319 files []discovery.SkillFile, renderedSkillMD string, extraFiles []discovery.SkillFile,
320 apiClient *api.Client, hostname, owner, repo string) {
321
322 // Show the file tree to stderr so it persists above the prompt
323 fmt.Fprintf(opts.IO.ErrOut, "\n%s\n", cs.Bold(skill.DisplayName()+"/"))
324 renderFileTree(opts.IO.ErrOut, cs, files)
325 fmt.Fprintln(opts.IO.ErrOut)
326
327 // Build choices: SKILL.md first, then extra files
328 choices := make([]string, 0, len(extraFiles)+1)
329 choices = append(choices, "SKILL.md")
330 for _, f := range extraFiles {
331 choices = append(choices, f.Path)
332 }
333
334 // Save original stdout. StopPager closes IO.Out, so we need to
335 // restore a working writer before each StartPager call.
336 originalOut := opts.IO.Out
337
338 for {
339 // Restore original Out before each pager cycle. StartPager replaces
340 // IO.Out with a pipe; StopPager closes that pipe but does not
341 // restore the original. The original writer remains valid.
342 opts.IO.Out = originalOut
343
344 idx, err := opts.Prompter.Select("View a file (Esc to exit):", "", choices)
345 if err != nil {
346 return // Prompter returns error on Esc/Ctrl-C; treat as graceful exit
347 }
348
349 var content string
350
351 if idx == 0 {
352 content = renderedSkillMD
353 } else {
354 selectedFile := extraFiles[idx-1]
355
356 // Fetch on demand; don't hold blob data in memory
357 fileContent, fetchErr := discovery.FetchBlob(apiClient, hostname, owner, repo, selectedFile.SHA)
358 if fetchErr != nil {
359 fmt.Fprintf(opts.IO.ErrOut, "%s could not fetch %s: %v\n", cs.Red("!"), selectedFile.Path, fetchErr)
360 continue
361 }
362 content = renderSelectedFilePreview(opts, selectedFile.Path, fileContent.String())
363 if !strings.HasSuffix(content, "\n") {
364 content += "\n"
365 }
366 }
367
368 if err := opts.IO.StartPager(); err != nil {
369 fmt.Fprintf(opts.IO.ErrOut, "starting pager failed: %v\n", err)
370 }
371 fmt.Fprint(opts.IO.Out, content)
372 opts.IO.StopPager()
373 }
374}
375

Callers 1

previewRunFunction · 0.85

Calls 10

FetchBlobFunction · 0.92
renderFileTreeFunction · 0.85
BoldMethod · 0.80
RedMethod · 0.80
StartPagerMethod · 0.80
StopPagerMethod · 0.80
DisplayNameMethod · 0.65
SelectMethod · 0.65
StringMethod · 0.65

Tested by

no test coverage detected