handle line breaks in clues

This commit is contained in:
cjdenio committed 2026-09-29 13:47:29 -04:00
1 parent 21f9caec34
commit c139490dc2
5 files changed
+70 -12

No files matched your search

-1
View File
@@ -10,7 +10,6 @@ Very silly terminal-based crossword solver. It can play .puz / .ipuz files from
todo
- correctly calculate uiHeight with multi-line clues
- timer
- reveal grid/word
- .puz checksums
+8 -3
View File
@@ -13,6 +13,11 @@ import (
"golang.org/x/term"
)
func getTermWidth() int {
w, _, _ := term.GetSize(int(os.Stdin.Fd()))
return w
}
func main() {
defer func() {
if r := recover(); r != nil {
@@ -72,7 +77,7 @@ func main() {
}
}
uiHeight := state.RenderUI(os.Stdout)
uiHeight := state.RenderUI(os.Stdout, getTermWidth())
scanner := bufio.NewScanner(os.Stdin)
scanner.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) {
@@ -108,13 +113,13 @@ func main() {
state.SelectedCell = -1
fmt.Printf("\r\x1b[%dA", uiHeight)
fmt.Print("\x1b[J")
state.RenderUI(os.Stdout)
state.RenderUI(os.Stdout, getTermWidth())
return
}
fmt.Printf("\r\x1b[%dA", uiHeight)
fmt.Print("\x1b[J")
uiHeight = state.RenderUI(os.Stdout)
uiHeight = state.RenderUI(os.Stdout, getTermWidth())
}
}
+50 -5
View File
@@ -32,6 +32,47 @@ type State struct {
RebusConfirmation bool
}
func RenderWithLineWrap(s string, width int) (out string, lines int) {
builder := strings.Builder{}
runes := []rune(s)
counter := 0
lines = 1
for i := 0; i < len(runes); i++ {
char := runes[i]
if char == '\n' {
builder.WriteString("\r\n")
lines++
counter = 0
continue
}
if char == '\r' && i < len(runes)-1 && runes[i+1] == '\n' {
builder.WriteString("\r\n")
lines++
counter = 0
i++
continue
}
builder.WriteRune(char)
counter++
if counter >= width && i < len(runes)-1 {
lines++
builder.WriteString("\r\n")
counter = 0
}
}
builder.WriteString("\r\n")
out = builder.String()
return
}
func NewState(puzzle *puz.Puzzle) *State {
return &State{
Puzzle: puzzle,
@@ -243,7 +284,7 @@ func (state *State) CheckWord(clue *puz.Clue) {
}
}
func (state *State) RenderUI(w io.Writer) int {
func (state *State) RenderUI(w io.Writer, width int) int {
if state.RebusConfirmation {
fmt.Fprint(w, "This puzzle contains a rebus. This tool does not support rebuses.\r\nPress 'y' to continue anyway, or press any other key to exit.\r\n")
return 2
@@ -258,12 +299,16 @@ func (state *State) RenderUI(w io.Writer) int {
fmt.Fprint(w, state.RenderPuzzle()+"\r\n")
uiHeight += state.Puzzle.Height + 3
if state.SelectedClue != nil {
directionStr := "down"
if state.SelectedClue.Direction == puz.DirectionAcross {
fmt.Fprintf(w, "%d-across: %s\r\n\r\n", state.SelectedClue.Number, state.SelectedClue.Clue)
} else {
fmt.Fprintf(w, "%d-down: %s\r\n\r\n", state.SelectedClue.Number, state.SelectedClue.Clue)
directionStr = "across"
}
uiHeight += 2
clueStr, clueLines := RenderWithLineWrap(fmt.Sprintf("%d-%s: %s", state.SelectedClue.Number, directionStr, state.SelectedClue.Clue), width)
w.Write([]byte(clueStr))
uiHeight += clueLines
io.WriteString(w, "\r\n")
uiHeight += 1
}
fmt.Fprintf(w, "%s\r\n", state.Puzzle.Copyright)
uiHeight += 1
+8
View File
@@ -3,6 +3,7 @@ package puz
import (
"encoding/json"
"errors"
"slices"
"strconv"
"strings"
)
@@ -16,6 +17,7 @@ type iPuzClue struct {
Clue string `json:"clue"`
}
type iPuzFile struct {
Kind []string `json:"kind"`
Title string `json:"title"`
Author string `json:"author"`
Copyright string `json:"copyright"`
@@ -32,6 +34,12 @@ func ParseIPuz(file []byte) (*Puzzle, error) {
return nil, err
}
if len(parsed.Kind) == 0 || !slices.ContainsFunc(parsed.Kind, func(k string) bool {
return strings.HasPrefix(k, "http://ipuz.org/crossword")
}) {
return nil, errors.New("ipuz file is not a crossword")
}
puzzle := new(Puzzle)
puzzle.Title = parsed.Title
+4 -3
View File
@@ -39,7 +39,8 @@ func main() {
io.WriteString(s, "\x1b[?25h")
}()
uiHeight := state.RenderUI(s)
pty, _, _ := s.Pty() // TODO: actually handle terminal size changes
uiHeight := state.RenderUI(s, pty.Window.Width)
scanner := bufio.NewScanner(s)
scanner.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) {
@@ -71,14 +72,14 @@ func main() {
state.SelectedCell = -1
fmt.Fprintf(s, "\r\x1b[%dA", uiHeight)
fmt.Fprint(s, "\x1b[J")
state.RenderUI(s)
state.RenderUI(s, pty.Window.Width)
break
}
fmt.Fprintf(s, "\r\x1b[%dA", uiHeight)
fmt.Fprint(s, "\x1b[J")
uiHeight = state.RenderUI(s)
uiHeight = state.RenderUI(s, pty.Window.Width)
}
log.Printf("%s disconnected\n", s.RemoteAddr().String())