package cmd import ( "encoding/json" "fmt" "os" "github.com/zk-org/zk/internal/adapter/fzf" "github.com/zk-org/zk/internal/cli" "github.com/zk-org/zk/internal/core" "github.com/zk-org/zk/internal/util/errors" "github.com/zk-org/zk/internal/util/strings" ) // Graph produces a directed graph of the notes matching a set of criteria. type Graph struct { Format string `group:format short:f help:"Format of the graph among: json." enum:"json" required` Quiet bool `group:format short:q help:"Do not print the total number of notes found."` cli.Filtering } func (cmd *Graph) Run(container *cli.Container) error { notebook, err := container.CurrentNotebook() if err != nil { return err } format, err := notebook.NewNoteFormatter("{{json .}}") if err != nil { return err } findOpts, err := cmd.Filtering.NewNoteFindOpts(notebook) if err != nil { return errors.Wrapf(err, "incorrect criteria") } notes, err := notebook.FindNotes(findOpts) if err != nil { return err } noteIDs := []core.NoteID{} for _, note := range notes { noteIDs = append(noteIDs, note.ID) } links, err := notebook.FindLinksBetweenNotes(noteIDs) if err != nil { return err } filter := container.NewNoteFilter(fzf.NoteFilterOpts{ Interactive: cmd.Interactive, AlwaysFilter: false, NotebookDir: notebook.Path, }) notes, err = filter.Apply(notes) if err != nil { if err == fzf.ErrCancelled { return nil } return err } fmt.Print("{\n \"notes\": [\n") for i, note := range notes { if i > 0 { fmt.Print(",\n") } ft, err := format(note) if err != nil { return err } fmt.Printf(" %s", ft) } fmt.Print("\n ],\n \"links\": [\n") for i, link := range links { if i > 0 { fmt.Print(",\n") } ft, err := json.Marshal(link) if err != nil { return err } fmt.Printf(" %s", string(ft)) } fmt.Print("\n ]\n}\n") if err == nil && !cmd.Quiet { count := len(notes) fmt.Fprintf(os.Stderr, "\n\nFound %d %s\n", count, strings.Pluralize("note", count)) } return err }