@oh-my-pi/hashline 17.2.14 → 17.3.0
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 +17 -0
- package/dist/types/apply.d.ts +13 -15
- package/dist/types/format.d.ts +5 -0
- package/dist/types/messages.d.ts +25 -27
- package/dist/types/syntax.d.ts +8 -7
- package/package.json +3 -3
- package/src/apply.ts +541 -966
- package/src/format.ts +14 -2
- package/src/messages.ts +52 -52
- package/src/prompt.md +33 -31
- package/src/syntax.ts +33 -7
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [17.3.0] - 2026-08-13
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Repaired mis-set replacement ranges using exact outside-row matches, indentation, tree-sitter structure, and a narrow pure-closer shape: opening comment fences and other syntax-essential edges are retained only when a parse-valid candidate satisfies those constraints; ambiguous placements are rejected.
|
|
10
|
+
|
|
11
|
+
## [17.2.15] - 2026-08-12
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- Added a post-apply parse advisory warning that alerts users when an applied edit fails to parse (despite the pre-edit content parsing successfully), helping catch balance-neutral misplacements that previously failed silently.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Fixed a bug where Rust lifetimes (e.g., `'static`) were incorrectly parsed as starting a string literal, which blinded the delimiter-balance scanner and could lead to silent signature deletions. Single-quote lexing on `.rs` files is now language-aware and correctly distinguishes lifetimes from character literals.
|
|
20
|
+
- Fixed an issue where terminal newlines in files were incorrectly exposed as editable blank rows.
|
|
21
|
+
|
|
5
22
|
## [17.2.12] - 2026-08-08
|
|
6
23
|
|
|
7
24
|
### Breaking Changes
|
package/dist/types/apply.d.ts
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
* post-edit lines plus any diagnostic warnings. Pure function: no FS, no
|
|
4
4
|
* mutation of the input.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* Mis-set replacement range boundaries are repaired by bounded candidate
|
|
7
|
+
* search. Exact line equality, indentation, tree-sitter structure, and a
|
|
8
|
+
* narrow pure-closer shape gate constrain candidates; tree-sitter validates
|
|
9
|
+
* the selected result.
|
|
9
10
|
*/
|
|
10
11
|
import type { ApplyResult, Clipboard, Edit } from "./types.js";
|
|
11
12
|
/** A line that is nothing but closing delimiters: `}`, `)`, `];`, `})`, `},`. */
|
|
@@ -21,11 +22,10 @@ export interface ApplyEditsOptions {
|
|
|
21
22
|
/** Anonymous `PASTE` with an empty register: `throw` (default) or `drop` (streaming previews). An empty named-register paste never throws — it warns and pastes nothing. */
|
|
22
23
|
onEmptyPaste?: "throw" | "drop";
|
|
23
24
|
/**
|
|
24
|
-
* Target
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* no veto and the delimiter heuristics decide alone.
|
|
25
|
+
* Target path used to infer a language for the tree-sitter syntax probe.
|
|
26
|
+
* Required for syntax-essential boundary retention and post-apply syntax
|
|
27
|
+
* advisories. Without it, only exact-text boundary normalization and its
|
|
28
|
+
* evidence-complete rejections run.
|
|
29
29
|
*/
|
|
30
30
|
path?: string;
|
|
31
31
|
}
|
|
@@ -35,12 +35,10 @@ export interface ApplyEditsOptions {
|
|
|
35
35
|
* Returns the post-edit text and the first changed line number (1-indexed).
|
|
36
36
|
* Throws if an anchor is out of bounds.
|
|
37
37
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* authored result does not parse — or the language is unknown to the parser, so
|
|
44
|
-
* balance arithmetic is the sole evidence — do the closer-spare repairs run.
|
|
38
|
+
* Mis-set replacement boundaries are repaired by {@link repairBoundaryVariants}
|
|
39
|
+
* when `options.path` lets tree-sitter judge the result. A parsing authored
|
|
40
|
+
* result is never second-guessed. For a broken result, only syntax-essential
|
|
41
|
+
* edge retention with matching indentation and exact outside-row echo removal
|
|
42
|
+
* are considered; every selected candidate must parse.
|
|
45
43
|
*/
|
|
46
44
|
export declare function applyEdits(text: string, edits: readonly Edit[], options?: ApplyEditsOptions): ApplyResult;
|
package/dist/types/format.d.ts
CHANGED
|
@@ -77,5 +77,10 @@ export declare function describeAnchorExamples(linePrefix?: string): string;
|
|
|
77
77
|
export declare function formatHashlineHeader(filePath: string, fileHash: string): string;
|
|
78
78
|
/** Formats a single numbered line as `LINE:TEXT`. */
|
|
79
79
|
export declare function formatNumberedLine(lineNumber: number, line: string): string;
|
|
80
|
+
/**
|
|
81
|
+
* Split LF-delimited file text into lines hashline anchors can address.
|
|
82
|
+
* A terminal newline terminates the preceding line; it is not content.
|
|
83
|
+
*/
|
|
84
|
+
export declare function splitAddressableFileLines(text: string): string[];
|
|
80
85
|
/** Format file text with hashline-mode line-number prefixes for display. */
|
|
81
86
|
export declare function formatNumberedLines(text: string, startLine?: number): string;
|
package/dist/types/messages.d.ts
CHANGED
|
@@ -86,46 +86,44 @@ export declare function pasteAfterBlockCloserLoweredWarning(line: number): strin
|
|
|
86
86
|
/** Register `PUT >N*` anchor unresolvable; applied as `PUT >N`. */
|
|
87
87
|
export declare function pasteAfterBlockUnresolvedLoweredWarning(line: number): string;
|
|
88
88
|
/**
|
|
89
|
-
* A one-sided boundary echo
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* edit is rejected instead of repaired.
|
|
89
|
+
* A one-sided exact boundary echo cannot cover the selected range after the
|
|
90
|
+
* duplicated body rows are removed. Applying or dropping it would lose
|
|
91
|
+
* distinct range content, so the edit is rejected unless a parse-restoring
|
|
92
|
+
* boundary combination proves another reading.
|
|
94
93
|
*/
|
|
95
94
|
export declare function ambiguousBoundaryEchoMessage(startLine: number, endLine: number, side: "leading" | "trailing", count: number): string;
|
|
96
95
|
/**
|
|
97
|
-
* A
|
|
98
|
-
*
|
|
99
|
-
* terminate: the payload has no unmatched opener for them and its indentation
|
|
100
|
-
* is not deeper than the closer. Sparing the closer would have to guess
|
|
101
|
-
* whether the payload belongs before it (inside the block) or after it (a
|
|
102
|
-
* sibling), so the edit is rejected instead of repaired.
|
|
96
|
+
* A syntax-essential selected edge can be retained on either side of the
|
|
97
|
+
* payload, but indentation does not establish which placement was intended.
|
|
103
98
|
*/
|
|
104
|
-
export declare function
|
|
99
|
+
export declare function ambiguousBoundaryPlacementMessage(startLine: number, endLine: number): string;
|
|
105
100
|
/**
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
* the construct above" mistake — but the payload's indentation claims a depth
|
|
109
|
-
* inside the block those closers terminate, so whether the new content
|
|
110
|
-
* belongs before or after the spared closer is ambiguous. Rejected instead of
|
|
111
|
-
* repaired; the at-or-above-depth reading is auto-repaired by sparing the
|
|
112
|
-
* closer ahead of the payload.
|
|
101
|
+
* Exact-text boundary rows were removed because the remaining payload covers
|
|
102
|
+
* the selected range and the same rows already survive immediately outside it.
|
|
113
103
|
*/
|
|
114
|
-
export declare function
|
|
104
|
+
export declare function textualBoundaryEchoWarning(startLine: number, leading: number, trailing: number): string;
|
|
115
105
|
/**
|
|
116
|
-
* A replacement range
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
* and opener/closer text shape cannot prove a syntactic block (the braces may
|
|
121
|
-
* be literal prose), so the edit applies as authored and the author decides.
|
|
106
|
+
* A replacement range's boundary disposition was corrected by the
|
|
107
|
+
* syntax-probe-judged search: syntax-essential source boundary rows were
|
|
108
|
+
* retained, or exact body echoes of surviving outside rows were removed. The
|
|
109
|
+
* authored result did not parse and the selected result does.
|
|
122
110
|
*/
|
|
123
|
-
export declare function
|
|
111
|
+
export declare function boundaryVariantRepairWarning(startLine: number, kept: number, dropped: number): string;
|
|
112
|
+
/**
|
|
113
|
+
* The applied result no longer parses while the pre-edit content did: the
|
|
114
|
+
* patch introduced a syntax error. Advisory, never a rejection — the applier
|
|
115
|
+
* honors the authored edit — but the breakage is machine-confirmed by
|
|
116
|
+
* tree-sitter and surfaced in the same response instead of waiting for a
|
|
117
|
+
* compiler pass.
|
|
118
|
+
*/
|
|
119
|
+
export declare function editBrokeParseWarning(firstChangedLine: number | undefined): string;
|
|
124
120
|
/**
|
|
125
121
|
* Internal invariant: `applyEdits` received an unresolved block edit;
|
|
126
122
|
* `resolveBlockEdits` must run first.
|
|
127
123
|
*/
|
|
128
124
|
export declare const UNRESOLVED_BLOCK_INTERNAL = "internal error: unresolved block edit reached the applier (resolveBlockEdits was not run).";
|
|
125
|
+
/** Internal invariant: clipboard edits must be concrete before application. */
|
|
126
|
+
export declare const UNRESOLVED_CLIPBOARD_INTERNAL = "internal error: unresolved clipboard edit reached the applier (resolveClipboardEdits was not run).";
|
|
129
127
|
/** `REM` received a body row or coexists with line edits. */
|
|
130
128
|
export declare const REM_TAKES_NO_BODY = "`REM` deletes the whole file and takes no body rows or line ops. Issue it alone under the header.";
|
|
131
129
|
/** `MV` received a body row. */
|
package/dist/types/syntax.d.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Syntax probe for candidate edit results, via the native tree-sitter parser.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* heuristics as the only available evidence.
|
|
4
|
+
* Replacement-boundary repair uses parsing as its semantic filter: exact
|
|
5
|
+
* outside-row equality may justify dropping a duplicated payload edge, while
|
|
6
|
+
* retaining a selected source boundary additionally requires source-range
|
|
7
|
+
* structure, indentation, or a narrow pure-closer shape. An unrecognized
|
|
8
|
+
* language yields no structural proof, so only evidence-complete textual
|
|
9
|
+
* normalization remains available.
|
|
11
10
|
*/
|
|
11
|
+
/** Syntactic node boundaries outside a visible source range. */
|
|
12
|
+
export declare function enclosingBoundaries(lines: readonly string[], path: string, startLine: number, endLine: number): readonly number[];
|
|
12
13
|
/**
|
|
13
14
|
* `true` when `text` parses without a syntax error under the language inferred
|
|
14
15
|
* from `path`. `false` covers "does not parse" and "cannot tell" alike — no
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/hashline",
|
|
4
|
-
"version": "17.
|
|
4
|
+
"version": "17.3.0",
|
|
5
5
|
"description": "Hashline: a compact, line-anchored patch language and applier. Pluggable FS/IO so it works over disk, in-memory, or any custom backend.",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"fmt": "biome format --write ."
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@oh-my-pi/pi-natives": "17.
|
|
37
|
-
"@oh-my-pi/pi-utils": "17.
|
|
36
|
+
"@oh-my-pi/pi-natives": "17.3.0",
|
|
37
|
+
"@oh-my-pi/pi-utils": "17.3.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/bun": "^1.3.14"
|