@fffangchenghao/dsh-latex-look 0.3.3 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/SKILL.md +1 -1
- package/bin/latex-look.mjs +9 -4
- package/cordis.patch.yml +1 -1
- package/index.js +9 -4
- package/lib/core.mjs +21 -14
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.5
|
|
4
|
+
|
|
5
|
+
- **The tool reports facts, not advice.** When the point lookup finds a rule it now
|
|
6
|
+
says what it measured and stops: `ink at this point: horizontal rule at y=47pt,
|
|
7
|
+
76% of page width`, then either `drawn by line 15: \rule{...}` or `nearest source
|
|
8
|
+
line 40 contains no rule command ... the document body does not draw this rule`.
|
|
9
|
+
The previous wording told the reader to go and look at `\pagestyle` /
|
|
10
|
+
`\headrulewidth`; that is knowledge about typography, not an observation, and the
|
|
11
|
+
tool is the wrong place for it — it lives in `SKILL.md`, where the agent reads it
|
|
12
|
+
and decides.
|
|
13
|
+
- The ink probe searches a ±4 pt band instead of one pixel row. Clicking a line is
|
|
14
|
+
routinely a point or two off, and a miss left the caller trusting the locate answer
|
|
15
|
+
this check exists to challenge. The finding reports the rule's own y, so a query
|
|
16
|
+
two points away still lands on the truth.
|
|
17
|
+
|
|
18
|
+
## 0.3.4
|
|
19
|
+
|
|
20
|
+
- Fix the bundle patch for a scoped package name: `name: @scope/pkg` is not valid
|
|
21
|
+
YAML, because `@` is a reserved indicator, so the installer rejected the package
|
|
22
|
+
with `bad indentation of a mapping entry`. Quoted. 0.3.3 installs nowhere.
|
|
23
|
+
|
|
3
24
|
## 0.3.3
|
|
4
25
|
|
|
5
26
|
- **Moved to a scope: `@fffangchenghao/dsh-latex-look`.** The flat name
|
package/SKILL.md
CHANGED
|
@@ -170,7 +170,7 @@ document is broken, suspect one of these:
|
|
|
170
170
|
| Jumped to another page | `[htbp]` + `\FloatBarrier`; or `\usepackage{float}` + `[H]` |
|
|
171
171
|
| Adding a caption pushed a near-full-page figure off the page, leaving half a page blank | the figure was already as tall as the text block, so a few millimetres of caption cannot fit above it. Wrapping it in `minipage` makes it unbreakable. Make that figure a float (`\begin{figure}[!tbp]`) so the text after it fills the page and the figure starts the next one |
|
|
172
172
|
| Caption orphaned on the next page | wrap figure+caption in one `minipage` — a caption is not tied to its graphic by default |
|
|
173
|
-
| "Delete the line at the top of the page" and
|
|
173
|
+
| "Delete the line at the top of the page", and the point lookup reports `the document body does not draw this rule` | the rule comes from the page style. It is `\pagestyle{fancy}` / `\pagestyle{headings}` with the head rule still on, or a `\rule`/`\hrule` in a `\markboth`-style macro. Fix it with `\fancyhf{}` plus `\renewcommand{\headrulewidth}{0pt}`, or switch to `\pagestyle{plain}`. Do **not** edit the line the lookup named (`\end{document}`); it is only the nearest box. When the rule *is* typed in the body, the lookup names it instead: `drawn by line 15: \rule{\linewidth}{0.4pt}`, and that is the line to change |
|
|
174
174
|
| A figure sits above the chapter title on a chapter's first page | a top float won the opening page. `\let\origchapter\chapter\renewcommand{\chapter}{\suppressfloats[t]\origchapter}` (no `@` in the name, or wrap it in `\makeatletter`) forbids top floats on every chapter opening, now and for chapters added later |
|
|
175
175
|
| Numbers run backwards: 图 3-4 on one page, 图 3-3 on the next | you floated one object but left its numbered neighbours inline. A float is placed later than an inline object that follows it in the source, and the reader turns the page to see 3-4 before 3-3. Floats of the same class keep their relative order, so float the **whole run** — never a float mixed into inline siblings. Check with `latex_look --sequence 图` after any change to how objects are placed |
|
|
176
176
|
| Too much space around it | `\setlength{\intextsep}{6pt}`, `\setlength{\textfloatsep}{10pt}` |
|
package/bin/latex-look.mjs
CHANGED
|
@@ -83,11 +83,16 @@ function summary(r) {
|
|
|
83
83
|
const at = typeof h.x === 'number' && typeof h.y === 'number' ? ` x=${h.x.toFixed(1)} y=${h.y.toFixed(1)}` : ''
|
|
84
84
|
L.push(` ${h.file}:${h.line} → p${h.page}${at}${fixed}`)
|
|
85
85
|
if (h.ink && h.ink.kind === 'rule' && h.ink.origin === 'command' && h.ink.sourceLine) {
|
|
86
|
-
L.push(` ^
|
|
86
|
+
L.push(` ^ ink at this point: horizontal rule at y=${h.ink.y}pt, ${Math.round(h.ink.span * 100)}% of page width`)
|
|
87
|
+
L.push(` drawn by line ${h.ink.sourceLine.line}: ${h.ink.sourceLine.text}`)
|
|
87
88
|
} else if (h.ink && h.ink.kind === 'rule') {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
L.push(
|
|
89
|
+
// Facts only. What to do about it is the reader's knowledge, not this tool's,
|
|
90
|
+
// and a hint here would be wrong on any document that does not match the guess.
|
|
91
|
+
L.push(` ^ ink at this point: horizontal rule at y=${h.ink.y}pt, ${Math.round(h.ink.span * 100)}% of page width`)
|
|
92
|
+
L.push(` nearest source line ${h.line} contains no rule command, and neither does any line within 4 of it`)
|
|
93
|
+
L.push(' the document body does not draw this rule')
|
|
94
|
+
} else if (h.ink && h.ink.kind === 'blank') {
|
|
95
|
+
L.push(' ^ ink at this point: none (blank paper; the nearest box belongs to a different spot)')
|
|
91
96
|
}
|
|
92
97
|
}
|
|
93
98
|
}
|
package/cordis.patch.yml
CHANGED
package/index.js
CHANGED
|
@@ -128,11 +128,16 @@ function format(r) {
|
|
|
128
128
|
: ''
|
|
129
129
|
L.push(` ${h.file}:${h.line} → page ${h.page}${y}${fixed}`)
|
|
130
130
|
if (h.ink && h.ink.kind === 'rule' && h.ink.origin === 'command' && h.ink.sourceLine) {
|
|
131
|
-
L.push(` ^
|
|
131
|
+
L.push(` ^ ink at this point: horizontal rule at y=${h.ink.y}pt, ${Math.round(h.ink.span * 100)}% of page width`)
|
|
132
|
+
L.push(` drawn by line ${h.ink.sourceLine.line}: ${h.ink.sourceLine.text}`)
|
|
132
133
|
} else if (h.ink && h.ink.kind === 'rule') {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
L.push(
|
|
134
|
+
// Facts only: what to do about a rule is the reader's knowledge, not the
|
|
135
|
+
// tool's. A hint here would be wrong on any document that does not match it.
|
|
136
|
+
L.push(` ^ ink at this point: horizontal rule at y=${h.ink.y}pt, ${Math.round(h.ink.span * 100)}% of page width`)
|
|
137
|
+
L.push(` nearest source line ${h.line} contains no rule command, and neither does any line within 4 of it`)
|
|
138
|
+
L.push(' the document body does not draw this rule')
|
|
139
|
+
} else if (h.ink && h.ink.kind === 'blank') {
|
|
140
|
+
L.push(' ^ ink at this point: none (blank paper; the nearest box belongs to a different spot)')
|
|
136
141
|
}
|
|
137
142
|
}
|
|
138
143
|
}
|
package/lib/core.mjs
CHANGED
|
@@ -824,27 +824,34 @@ export function classifyInk(raster, { x, y, dpi = 72 } = {}) {
|
|
|
824
824
|
const o = (yy * raster.width + xx) * 3
|
|
825
825
|
return raster.data[o] < 200 && raster.data[o + 1] < 200 && raster.data[o + 2] < 200
|
|
826
826
|
}
|
|
827
|
-
|
|
828
|
-
let bestRow = py
|
|
829
|
-
for (let yy = Math.max(0, py - 1); yy <= Math.min(raster.height - 1, py + 1); yy++) {
|
|
827
|
+
const rowInk = (yy) => {
|
|
830
828
|
let count = 0
|
|
831
829
|
for (let xx = 0; xx < raster.width; xx++) if (at(xx, yy)) count++
|
|
832
|
-
|
|
830
|
+
return count / raster.width
|
|
831
|
+
}
|
|
832
|
+
// Look for a rule in a band around the point, not on one exact row: a reader who
|
|
833
|
+
// clicks a line is routinely a point or two away, and a miss here would leave the
|
|
834
|
+
// caller trusting a locate answer this check exists to challenge.
|
|
835
|
+
const bandPt = 4
|
|
836
|
+
const band = Math.max(1, Math.round((bandPt / 72) * dpi))
|
|
837
|
+
let best = { span: 0, row: py }
|
|
838
|
+
for (let yy = Math.max(0, py - band); yy <= Math.min(raster.height - 1, py + band); yy++) {
|
|
839
|
+
const span = rowInk(yy)
|
|
840
|
+
if (span > best.span) best = { span, row: yy }
|
|
841
|
+
}
|
|
842
|
+
let thin = true
|
|
843
|
+
for (const yy of [best.row - 3, best.row + 3]) {
|
|
844
|
+
if (yy < 0 || yy >= raster.height) continue
|
|
845
|
+
if (rowInk(yy) > 0.3) { thin = false; break }
|
|
846
|
+
}
|
|
847
|
+
if (best.span > 0.35 && thin) {
|
|
848
|
+
return { kind: 'rule', span: Number(best.span.toFixed(2)), y: Number(((best.row / dpi) * 72).toFixed(1)) }
|
|
833
849
|
}
|
|
834
|
-
const span = bestSpan / raster.width
|
|
835
850
|
let near = 0
|
|
836
851
|
for (let yy = Math.max(0, py - 4); yy <= Math.min(raster.height - 1, py + 4); yy++) {
|
|
837
852
|
for (let xx = Math.max(0, px - 4); xx <= Math.min(raster.width - 1, px + 4); xx++) if (at(xx, yy)) near++
|
|
838
853
|
}
|
|
839
|
-
|
|
840
|
-
for (const yy of [bestRow - 3, bestRow + 3]) {
|
|
841
|
-
if (yy < 0 || yy >= raster.height) continue
|
|
842
|
-
let count = 0
|
|
843
|
-
for (let xx = 0; xx < raster.width; xx++) if (at(xx, yy)) count++
|
|
844
|
-
if (count / raster.width > 0.3) { thin = false; break }
|
|
845
|
-
}
|
|
846
|
-
const kind = span > 0.35 && thin ? 'rule' : near > 0 ? 'text' : 'blank'
|
|
847
|
-
return { kind, span: Number(span.toFixed(2)) }
|
|
854
|
+
return { kind: near > 0 ? 'text' : 'blank' }
|
|
848
855
|
}
|
|
849
856
|
|
|
850
857
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fffangchenghao/dsh-latex-look",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
4
4
|
"description": "DSH plugin: let an AI agent see a LaTeX document — compile it, render the page, locate the source line, and diff what an edit changed.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|