summaryrefslogtreecommitdiff
path: root/internal/hexaiaction/parse.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-09-06 13:19:01 +0300
committerPaul Buetow <paul@buetow.org>2025-09-06 13:19:01 +0300
commit04f290dbeeee8a6fcbc70fed253a968336bcb2ab (patch)
tree3ee23a4ac4bcc5b43b43697cfb0e905735fc6331 /internal/hexaiaction/parse.go
parent5e966f50111adf6e2cb2683fe588f6fe033fa931 (diff)
more tests
Diffstat (limited to 'internal/hexaiaction/parse.go')
-rw-r--r--internal/hexaiaction/parse.go69
1 files changed, 69 insertions, 0 deletions
diff --git a/internal/hexaiaction/parse.go b/internal/hexaiaction/parse.go
new file mode 100644
index 0000000..99e2b24
--- /dev/null
+++ b/internal/hexaiaction/parse.go
@@ -0,0 +1,69 @@
+package hexaiaction
+
+import (
+ "bufio"
+ "io"
+ "strings"
+
+ "codeberg.org/snonux/hexai/internal/textutil"
+)
+
+// ParseInput splits raw stdin into optional diagnostics and selection/code.
+// Format:
+//
+// Diagnostics:\n
+// <one per line>\n
+// <blank line> (optional)\n
+// <rest is selection/code>
+//
+// If the header is absent, the entire input is treated as selection.
+func ParseInput(r io.Reader) (InputParts, error) {
+ b, err := io.ReadAll(bufio.NewReader(r))
+ if err != nil {
+ return InputParts{}, err
+ }
+ raw := strings.TrimSpace(string(b))
+ if raw == "" {
+ return InputParts{Selection: ""}, nil
+ }
+ lines := strings.Split(raw, "\n")
+ // find a case-insensitive line equal to "diagnostics:"
+ diagsIdx := -1
+ for i, ln := range lines {
+ t := strings.TrimSpace(strings.ToLower(ln))
+ if t == "diagnostics:" {
+ diagsIdx = i
+ break
+ }
+ }
+ if diagsIdx < 0 {
+ return InputParts{Selection: raw}, nil
+ }
+ // collect diagnostics until a blank line or EOF
+ diags := []string{}
+ i := diagsIdx + 1
+ for ; i < len(lines); i++ {
+ t := strings.TrimSpace(lines[i])
+ if t == "" {
+ i++
+ break
+ }
+ diags = append(diags, t)
+ }
+ sel := strings.Join(lines[i:], "\n")
+ sel = strings.TrimSpace(sel)
+ return InputParts{Selection: sel, Diagnostics: diags}, nil
+}
+
+// ExtractInstruction mirrors the LSP instructionFromSelection behavior (subset),
+// scanning the first line for an instruction marker and removing it from the selection.
+func ExtractInstruction(sel string) (string, string) { return textutil.InstructionFromSelection(sel) }
+
+// findFirstInstructionInLine follows the same precedence as LSP:
+// - ;text; (strict)
+// - /* text */ (single-line)
+// - <!-- text --> (single-line)
+// - // text
+// - # text
+// - -- text
+// helpers moved to textutil