fix repl-block, check-tangle, commands: READMEs, exit codes, path resolution
repl-block: - Listing mode exits 0, not 1 (listing is not an error) - Dead lines parameter removed from find_by_function - Block listing goes to stderr (not stdout) so piped use works - Added README.org check-tangle: - Fixed tangle tool resolution: prefer local projects/tangle-tool/tangle - Fixed path resolution for relative and absolute tangle paths - Removed 2>/dev/null suppression so tangle errors are visible - Added README.org Commands: - Rewrote all three .opencode/commands/*.md with proper prompts
This commit is contained in:
@@ -3,6 +3,9 @@ description: Check paren balance in lisp blocks of .org files
|
||||
---
|
||||
|
||||
Run `projects/check-parens/check-parens` on the given .org files to verify all
|
||||
`#+begin_src lisp` blocks have balanced parentheses.
|
||||
`#+begin_src lisp` blocks have balanced parentheses. Uses SBCL's reader for
|
||||
100% accuracy — no false positives from string literals or character literals.
|
||||
|
||||
Exit 0 if all blocks balanced, 1 if any issues found.
|
||||
|
||||
Usage: /check-parens <file.org> [<file.org> ...]
|
||||
|
||||
@@ -3,6 +3,13 @@ description: Tangle an org file and compile the result
|
||||
---
|
||||
|
||||
Tangle an .org file to .lisp then compile with SBCL. Reports the first
|
||||
compile error. Exit 0 = clean, exit 1 = compilation error.
|
||||
compile error with line numbers. Exit 0 = clean compile, exit 1 = error.
|
||||
|
||||
Prepares code for commit by ensuring the tangled .lisp file is syntactically
|
||||
valid. Catches missing symbols, undefined functions, and type errors before
|
||||
they reach the running daemon.
|
||||
|
||||
Usage: /check-tangle <file.org>
|
||||
|
||||
Example:
|
||||
/check-tangle projects/passepartout/org/channel-tui-main.org
|
||||
|
||||
@@ -2,12 +2,16 @@
|
||||
description: Send a lisp block from an org file to the REPL
|
||||
---
|
||||
|
||||
Extract a `#+begin_src lisp` block from an .org file and send it to the
|
||||
running daemon REPL.
|
||||
Extract a `#+begin_src lisp` block from an .org file and pipe it to the
|
||||
running daemon REPL. Identify the block by function name or index.
|
||||
|
||||
The `--package` flag wraps the block in `(in-package ...)` so it evaluates
|
||||
in the right namespace — essential when the block references symbols from
|
||||
a specific package without the package prefix.
|
||||
|
||||
Usage: /repl-block <file.org> --function <name>
|
||||
/repl-block <file.org> --block <number>
|
||||
/repl-block <file.org> --function <name> --package <pkg>
|
||||
/repl-block <file.org> --block <number>
|
||||
|
||||
The --package flag wraps the block in an (in-package ...) form.
|
||||
Use --block to identify by 1-based index, --function to find by defun name.
|
||||
Example:
|
||||
/repl-block projects/passepartout/org/channel-tui-view.org --function view-status --package :passepartout.channel-tui
|
||||
|
||||
22
projects/check-tangle/README.org
Normal file
22
projects/check-tangle/README.org
Normal file
@@ -0,0 +1,22 @@
|
||||
#+TITLE: check-tangle
|
||||
|
||||
Tangle an .org file and compile the resulting .lisp with SBCL in one step.
|
||||
|
||||
== Usage
|
||||
|
||||
#+begin_src shell
|
||||
check-tangle org/file.org
|
||||
#+end_src
|
||||
|
||||
Exit 0 if compilation succeeds, 1 if tangling or compilation fails.
|
||||
|
||||
== What it checks
|
||||
|
||||
1. Reads the ~:tangle~ header from the org file to find the target .lisp path
|
||||
2. Runs ~tangle~ to generate the .lisp from the .org source
|
||||
3. Runs ~sbcl compile-file~ on the result
|
||||
4. Reports the first compile error if any
|
||||
|
||||
== Requires
|
||||
|
||||
Emacs (for tangling), SBCL (for compilation).
|
||||
@@ -28,13 +28,26 @@ fi
|
||||
|
||||
# Resolve relative tangle path
|
||||
ORG_DIR=$(dirname "$ORG_FILE")
|
||||
LISP_FILE=$(cd "$ORG_DIR" && realpath -m "$TANGLE" 2>/dev/null || echo "$ORG_DIR/$TANGLE")
|
||||
if [ "$TANGLE" = "${TANGLE#/}" ]; then
|
||||
# Relative path
|
||||
LISP_FILE=$(cd "$ORG_DIR" && realpath -m "$TANGLE" 2>/dev/null || echo "$ORG_DIR/$TANGLE")
|
||||
else
|
||||
# Absolute path
|
||||
LISP_FILE="$TANGLE"
|
||||
fi
|
||||
|
||||
echo "Tangling: $ORG_FILE → $LISP_FILE" >&2
|
||||
|
||||
# Tangle using opencode's tangle tool
|
||||
TANGLE_CMD=$(command -v tangle 2>/dev/null || echo "/home/user/.opencode/bin/tangle")
|
||||
if ! "$TANGLE_CMD" "$ORG_FILE" 2>/dev/null; then
|
||||
# Prefer the memex's own tangle tool, then fall back to PATH
|
||||
if [ -x "projects/tangle-tool/tangle" ]; then
|
||||
TANGLE_CMD="projects/tangle-tool/tangle"
|
||||
elif command -v tangle &>/dev/null; then
|
||||
TANGLE_CMD="tangle"
|
||||
else
|
||||
TANGLE_CMD="/home/user/.opencode/bin/tangle"
|
||||
fi
|
||||
|
||||
if ! "$TANGLE_CMD" "$ORG_FILE"; then
|
||||
echo "FAIL: Tangling $ORG_FILE failed" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
28
projects/repl-block/README.org
Normal file
28
projects/repl-block/README.org
Normal file
@@ -0,0 +1,28 @@
|
||||
#+TITLE: repl-block
|
||||
|
||||
Extract a ~#+begin_src lisp~ block from an .org file and output it to stdout,
|
||||
ready to pipe to ~repl~ or inspect.
|
||||
|
||||
== Usage
|
||||
|
||||
#+begin_src shell
|
||||
repl-block org/file.org --function foo | repl
|
||||
repl-block org/file.org --block 3
|
||||
repl-block org/file.org --function foo --package :my-package
|
||||
repl-block org/file.org # list all blocks
|
||||
#+end_src
|
||||
|
||||
== Identifying blocks
|
||||
|
||||
By function name (--function): scans all blocks for (defun <name> ...) and
|
||||
outputs the containing block. By index (--block): 1-based position in file.
|
||||
|
||||
The --package flag prepends an ~(in-package ...)~ form so the REPL evaluates
|
||||
in the right namespace.
|
||||
|
||||
Combine with ~repl~ to send a block directly to the daemon:
|
||||
repl-block org/channel-tui-view.org --function view-status --package :passepartout.channel-tui | repl
|
||||
|
||||
== Requires
|
||||
|
||||
Python 3. No dependencies.
|
||||
@@ -41,7 +41,7 @@ def extract_blocks(lines):
|
||||
return blocks
|
||||
|
||||
|
||||
def find_by_function(blocks, name, lines):
|
||||
def find_by_function(blocks, name):
|
||||
for line_no, body in blocks:
|
||||
for bline in body:
|
||||
if re.match(rf"\(def(un|macro|method|var|parameter|class|struct|package)\s+{re.escape(name)}\b", bline):
|
||||
@@ -76,7 +76,7 @@ def main():
|
||||
blocks = extract_blocks(lines)
|
||||
|
||||
if args.function:
|
||||
line_no, body = find_by_function(blocks, args.function, lines)
|
||||
line_no, body = find_by_function(blocks, args.function)
|
||||
if body is None:
|
||||
print(f"No block found containing function '{args.function}'", file=sys.stderr)
|
||||
return 1
|
||||
@@ -86,12 +86,12 @@ def main():
|
||||
print(f"Block {args.block} not found (file has {len(blocks)} blocks)", file=sys.stderr)
|
||||
return 1
|
||||
else:
|
||||
# Print listing
|
||||
# Print listing to stderr so piping still works
|
||||
for idx, (line_no, body) in enumerate(blocks, 1):
|
||||
first = (body or [""])[0][:60]
|
||||
print(f" {idx}: line {line_no}: {first}")
|
||||
print(f" {idx}: line {line_no}: {first}", file=sys.stderr)
|
||||
print(f"\n{len(blocks)} total blocks", file=sys.stderr)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
if args.package:
|
||||
pkg = args.package
|
||||
|
||||
Reference in New Issue
Block a user