// Package cmdutil provides shared boilerplate for LSP tool command binaries. package cmdutil import ( "encoding/json" "fmt" "os" "path/filepath" "strconv" "ollie/tools/lsp" ) // PositionArgs are the common args for position-based LSP commands. type PositionArgs struct { Path string `json:"path"` Line string `json:"line"` Col string `json:"col"` } // ResolvePosition converts the string fields to absolute path and 0-indexed ints. func (a PositionArgs) ResolvePosition() (file string, line, col int) { file, _ = filepath.Abs(a.Path) l, _ := strconv.Atoi(a.Line) c, _ := strconv.Atoi(a.Col) return file, l - 1, c - 1 } // Run is the common entry point for position-based LSP commands. // It handles --bridge, reads PositionArgs from stdin, dispatches the request, // and passes the result to format. If format is nil, raw JSON is printed. func Run(method string, format func(json.RawMessage)) { if len(os.Args) > 1 && os.Args[1] == "--bridge" { if err := lsp.RunBridge(); err != nil { fmt.Fprintf(os.Stderr, "bridge: %v\n", err) os.Exit(1) } return } var args PositionArgs if err := json.NewDecoder(os.Stdin).Decode(&args); err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } file, line, col := args.ResolvePosition() result, err := lsp.ClientRequest(&lsp.BridgeRequest{ Method: method, File: file, Line: line, Col: col, }) if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } if result == nil || string(result) == "null" { fmt.Printf("(no %s found)\n", method) return } if format != nil { format(result) } else { os.Stdout.Write(result) fmt.Println() } } // RunCustom handles --bridge and then calls fn for custom argument handling. // Use for commands that don't follow the simple position-args pattern // (e.g. diagnostics, rename, symbols). func RunCustom(fn func()) { if len(os.Args) > 1 && os.Args[1] == "--bridge" { if err := lsp.RunBridge(); err != nil { fmt.Fprintf(os.Stderr, "bridge: %v\n", err) os.Exit(1) } return } fn() }