@carlesandres/house 0.8.0 → 0.9.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 +26 -2
- package/README.md +13 -5
- package/dist/index.js +104 -41
- package/package.json +11 -11
package/CHANGELOG.md
CHANGED
|
@@ -2,10 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to house land here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html) from v0.1.0 onward.
|
|
4
4
|
|
|
5
|
-
The publish workflow (`.github/workflows/publish.yml`) runs
|
|
5
|
+
The publish workflow (`.github/workflows/publish.yml`) runs for a published release or a release-tag dispatch, builds per-platform binaries, publishes platform packages then the main package via Trusted Publisher, and lets GitHub auto-generate release notes from commit subjects; this file is the curated, narrative version.
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.9.0] — 2026-09-12
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Opening a selected file now hides the Sidebar by default so the Reader gets the full pane; set
|
|
14
|
+
`autoHideSidebar = false` or use `--no-auto-hide-sidebar` to keep the two-pane view.
|
|
15
|
+
- Release preparation now runs from a dispatchable GitHub workflow, and merging its PR creates and verifies the release, so publishing no longer depends on a clean local checkout or a long-running terminal.
|
|
16
|
+
- The publish job no longer waits for a GitHub `npm` environment reviewer, so creating the GitHub Release (or a `main` dispatch) is enough to ship. The environment still allows only `v*` tags and `main`.
|
|
17
|
+
- Empty CLI `--extensions` / `--show` again override file and env lists after the Effect 4.0.0-beta.107 bump, so an explicit empty allow-list still wins.
|
|
18
|
+
- House now runs on OpenTUI 0.5.9, matching `@house/ui` and the current renderer/input stack.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- Release preparation now creates GitHub-verified commits, so release pull requests satisfy the
|
|
23
|
+
repository's signed-commit rule and can be merged normally.
|
|
24
|
+
- Release preparation now rejects stale managed branches, requests maintainer review, and reports
|
|
25
|
+
dispatched CI on the pull request, so release approvals remain visible through GitHub and `gh`.
|
|
26
|
+
- Release preparation now passes GitHub authentication and step outputs through Turborepo, so
|
|
27
|
+
dispatches can create release pull requests and start their CI.
|
|
28
|
+
- Shift+A no longer drops a hidden-file selection when toggling hidden files back on, so the original file is reselected after the re-walk.
|
|
29
|
+
- Theme resolution now keeps 8-digit hex alpha from bundled palettes, so muted and border tokens in themes like Cursor stay distinct from opaque text.
|
|
30
|
+
|
|
31
|
+
|
|
9
32
|
## [0.8.0] — 2026-08-30
|
|
10
33
|
|
|
11
34
|
### Added
|
|
@@ -442,7 +465,8 @@ The v1 MVP, published as `@carlesandres/openmdr` on npm.
|
|
|
442
465
|
|
|
443
466
|
Search, stdin, URL fetching, cross-file link following, `$EDITOR` hand-off, syntax highlighting, persistent config, OS-appearance auto-detect, single-binary distribution (issue [#2](https://github.com/carlesandres/openmdr/issues/2)), Homebrew tap. All tracked.
|
|
444
467
|
|
|
445
|
-
[Unreleased]: https://github.com/carlesandres/house/compare/v0.
|
|
468
|
+
[Unreleased]: https://github.com/carlesandres/house/compare/v0.9.0...HEAD
|
|
469
|
+
[0.9.0]: https://github.com/carlesandres/house/compare/v0.8.0...v0.9.0
|
|
446
470
|
[0.8.0]: https://github.com/carlesandres/house/compare/v0.7.0...v0.8.0
|
|
447
471
|
[0.7.0]: https://github.com/carlesandres/house/compare/v0.6.0...v0.7.0
|
|
448
472
|
[0.6.0]: https://github.com/carlesandres/house/compare/v0.5.2...v0.6.0
|
package/README.md
CHANGED
|
@@ -68,6 +68,8 @@ house --serve README.md
|
|
|
68
68
|
| `--width <N>` | `80` | Reader wrap width used when wrapping is enabled |
|
|
69
69
|
| `--wrap` | off | Start with reader wrapping enabled |
|
|
70
70
|
| `--no-wrap` | off | Start with reader wrapping disabled |
|
|
71
|
+
| `--auto-hide-sidebar` | on | Hide the sidebar after explicitly opening a file |
|
|
72
|
+
| `--no-auto-hide-sidebar` | off | Keep the sidebar visible after explicitly opening a file |
|
|
71
73
|
| `--show <list>` | `""` | Reveal normally-skipped entries; comma-separated subset of `hidden`, `gitignored`. Use `--show ""` to clear. |
|
|
72
74
|
| `--root <dir>` | current directory | Discovery root to walk; overrides `defaultRoot` config/env |
|
|
73
75
|
| `--focus <mode>` | `sidebar` | Startup focus: `sidebar`, `reader`, or `filter`. `filter` opens the sidebar filter prompt immediately. |
|
|
@@ -97,27 +99,33 @@ tone = "dark"
|
|
|
97
99
|
extensions = []
|
|
98
100
|
width = 80
|
|
99
101
|
wrap = false
|
|
102
|
+
autoHideSidebar = true
|
|
100
103
|
show = ["hidden", "gitignored"]
|
|
101
104
|
focus = "sidebar"
|
|
102
105
|
defaultRoot = "cwd" # or "git"
|
|
103
106
|
order = "recently-modified" # or "tree"
|
|
104
107
|
```
|
|
105
108
|
|
|
106
|
-
Supported keys: `theme`, `tone`, `extensions`, `width`, `wrap`, `show`, `focus`, `defaultRoot`, `order`.
|
|
109
|
+
Supported keys: `theme`, `tone`, `extensions`, `width`, `wrap`, `autoHideSidebar`, `show`, `focus`, `defaultRoot`, `order`.
|
|
107
110
|
|
|
108
111
|
`show` is a list of normally-skipped categories to opt into. Known categories: `hidden` (dot-prefixed entries), `gitignored` (entries matched by a `.gitignore`). Default is the empty list. Hard skips (`node_modules`, `.git`, `.venv`) always apply.
|
|
109
112
|
|
|
110
113
|
Precedence, highest to lowest:
|
|
111
114
|
|
|
112
|
-
1. CLI flags (`--theme`, `--tone`, `--ext`, `--width`, `--wrap`, `--no-wrap`, `--show`, `--focus`, `--order`, `--root`)
|
|
113
|
-
2. Env vars (`HOUSE_THEME`, `HOUSE_TONE`, `HOUSE_EXTENSIONS`, `HOUSE_WIDTH`, `HOUSE_WRAP`, `HOUSE_SHOW`, `HOUSE_FOCUS`, `HOUSE_DEFAULT_ROOT`, `HOUSE_ORDER`)
|
|
115
|
+
1. CLI flags (`--theme`, `--tone`, `--ext`, `--width`, `--wrap`, `--no-wrap`, `--auto-hide-sidebar`, `--no-auto-hide-sidebar`, `--show`, `--focus`, `--order`, `--root`)
|
|
116
|
+
2. Env vars (`HOUSE_THEME`, `HOUSE_TONE`, `HOUSE_EXTENSIONS`, `HOUSE_WIDTH`, `HOUSE_WRAP`, `HOUSE_AUTO_HIDE_SIDEBAR`, `HOUSE_SHOW`, `HOUSE_FOCUS`, `HOUSE_DEFAULT_ROOT`, `HOUSE_ORDER`)
|
|
114
117
|
3. Config file
|
|
115
|
-
4. Built-in defaults (`opencode` / `dark` / `extensions = []` / `width = 80` / `wrap = false` / `show = []` / `focus = "sidebar"` / `defaultRoot = "cwd"` / `order = "recently-modified"`)
|
|
118
|
+
4. Built-in defaults (`opencode` / `dark` / `extensions = []` / `width = 80` / `wrap = false` / `autoHideSidebar = true` / `show = []` / `focus = "sidebar"` / `defaultRoot = "cwd"` / `order = "recently-modified"`)
|
|
116
119
|
|
|
117
120
|
`HOUSE_SHOW` takes a comma-separated list (`HOUSE_SHOW=hidden,gitignored`). For `show` specifically, each source completely replaces the next — categories don't merge across layers. Press `shift+a` in the TUI to round-trip between the configured set and the full vocabulary without editing config.
|
|
118
121
|
|
|
119
122
|
`width` is the fixed reader width used when wrapping is enabled. `wrap` controls startup mode; press `w` in the TUI to toggle reader wrapping for the current session without editing config.
|
|
120
123
|
|
|
124
|
+
`autoHideSidebar` hides the sidebar when you explicitly open a selected file with `↵`, `→`, `l`,
|
|
125
|
+
the command palette, or a matching filter Return. Selection movement still previews files without
|
|
126
|
+
hiding it. Press `s` or `/` to bring the sidebar back. Set the option to `false` to retain the
|
|
127
|
+
two-pane view after Open file.
|
|
128
|
+
|
|
121
129
|
`order` is the File Navigator browse order when no filter query is active. `recently-modified` (default) lists the most recently updated files first, using filesystem modification time, then tree order for ties. `tree` lists files before directories, alphabetically within each group, so current-directory files appear before nested subtrees. An active filter still ranks by relevance first.
|
|
122
130
|
|
|
123
131
|
The file is optional — a missing file is fine. Invalid keys, unknown themes, invalid `defaultRoot`, or malformed TOML fail loudly with a one-line error. Per-project config (`.house/config.toml`) and additional keys are deferred.
|
|
@@ -157,7 +165,7 @@ The footer only shows essential app controls (`W`, `q`, `tab`, `s`, `ctrl+p`) to
|
|
|
157
165
|
| `G` | Last file |
|
|
158
166
|
| `/` | Filter files (fuzzy match on path) |
|
|
159
167
|
| `A` | Toggle hidden + gitignored entries (session-only; round-trips with the configured `show`) |
|
|
160
|
-
| `↵` / `→` / `l` | Open file (focus reader)
|
|
168
|
+
| `↵` / `→` / `l` | Open file (focus reader and auto-hide the sidebar when enabled) |
|
|
161
169
|
|
|
162
170
|
### Reader
|
|
163
171
|
|
package/dist/index.js
CHANGED
|
@@ -3066,7 +3066,7 @@ import { useState as useState6 } from "react";
|
|
|
3066
3066
|
// package.json
|
|
3067
3067
|
var package_default = {
|
|
3068
3068
|
name: "@carlesandres/house",
|
|
3069
|
-
version: "0.
|
|
3069
|
+
version: "0.9.0",
|
|
3070
3070
|
description: "TUI-first markdown reader on opentui",
|
|
3071
3071
|
type: "module",
|
|
3072
3072
|
license: "MIT",
|
|
@@ -3134,15 +3134,15 @@ var package_default = {
|
|
|
3134
3134
|
"@carlesandres/house-linux-x64": "0.5.1"
|
|
3135
3135
|
},
|
|
3136
3136
|
dependencies: {
|
|
3137
|
-
"@effect/atom-react": "4.0.0-beta.
|
|
3138
|
-
"@opentui/core": "0.
|
|
3139
|
-
"@opentui/react": "0.
|
|
3137
|
+
"@effect/atom-react": "4.0.0-beta.107",
|
|
3138
|
+
"@opentui/core": "0.5.9",
|
|
3139
|
+
"@opentui/react": "0.5.9",
|
|
3140
3140
|
"@parcel/watcher": "2.6.0",
|
|
3141
3141
|
commander: "^14.0.3",
|
|
3142
|
-
effect: "4.0.0-beta.
|
|
3142
|
+
effect: "4.0.0-beta.107",
|
|
3143
3143
|
ignore: "^7.0.5",
|
|
3144
3144
|
marked: "^18.0.4",
|
|
3145
|
-
react: "19.2.
|
|
3145
|
+
react: "19.2.8",
|
|
3146
3146
|
scheduler: "0.27.0",
|
|
3147
3147
|
"string-width": "7.2.0",
|
|
3148
3148
|
"web-tree-sitter": "0.25.10"
|
|
@@ -3150,7 +3150,7 @@ var package_default = {
|
|
|
3150
3150
|
devDependencies: {
|
|
3151
3151
|
"@effect/language-service": "0.86.2",
|
|
3152
3152
|
"@types/bun": "1.3.14",
|
|
3153
|
-
"@types/react": "19.2.
|
|
3153
|
+
"@types/react": "19.2.18",
|
|
3154
3154
|
emulate: "0.9.0",
|
|
3155
3155
|
oxfmt: "0.51.0",
|
|
3156
3156
|
oxlint: "1.66.0",
|
|
@@ -3620,7 +3620,7 @@ var browserBindings = [
|
|
|
3620
3620
|
description: "Open file (focus reader)",
|
|
3621
3621
|
keys: ["return", "right", "l"],
|
|
3622
3622
|
when: inSidebar,
|
|
3623
|
-
run: (c) => c.
|
|
3623
|
+
run: (c) => c.openSelectedFile()
|
|
3624
3624
|
},
|
|
3625
3625
|
{
|
|
3626
3626
|
id: "serve.current",
|
|
@@ -3845,17 +3845,16 @@ var HARD_FALLBACK_RAW = {
|
|
|
3845
3845
|
syntaxPunctuation: "#D8DEE9"
|
|
3846
3846
|
};
|
|
3847
3847
|
var HEX_RE_INIT = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
|
|
3848
|
-
var
|
|
3849
|
-
const v =
|
|
3848
|
+
var normalizeHex = (value) => {
|
|
3849
|
+
const v = value.replace("#", "");
|
|
3850
3850
|
const expanded = v.length === 3 || v.length === 4 ? v.split("").map((c) => c + c).join("") : v;
|
|
3851
|
-
|
|
3852
|
-
return `#${rgb.toLowerCase()}`;
|
|
3851
|
+
return `#${expanded.toLowerCase()}`;
|
|
3853
3852
|
};
|
|
3854
3853
|
for (const v of Object.values(HARD_FALLBACK_RAW)) {
|
|
3855
3854
|
if (!HEX_RE_INIT.test(v))
|
|
3856
3855
|
throw new Error(`bad fallback hex: ${v}`);
|
|
3857
3856
|
}
|
|
3858
|
-
var HARD_FALLBACK = Object.fromEntries(Object.entries(HARD_FALLBACK_RAW).map(([k, v]) => [k,
|
|
3857
|
+
var HARD_FALLBACK = Object.fromEntries(Object.entries(HARD_FALLBACK_RAW).map(([k, v]) => [k, normalizeHex(v)]));
|
|
3859
3858
|
var TOKEN_FALLBACK = {
|
|
3860
3859
|
selectedListItemText: "text",
|
|
3861
3860
|
markdownText: "text",
|
|
@@ -3864,12 +3863,6 @@ var TOKEN_FALLBACK = {
|
|
|
3864
3863
|
};
|
|
3865
3864
|
var HEX_RE = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
|
|
3866
3865
|
var isHex = (value) => HEX_RE.test(value);
|
|
3867
|
-
var normalizeHex = (value) => {
|
|
3868
|
-
const v = value.replace("#", "");
|
|
3869
|
-
const expanded = v.length === 3 || v.length === 4 ? v.split("").map((c) => c + c).join("") : v;
|
|
3870
|
-
const rgb = expanded.length === 8 ? expanded.slice(0, 6) : expanded;
|
|
3871
|
-
return `#${rgb.toLowerCase()}`;
|
|
3872
|
-
};
|
|
3873
3866
|
var resolveSide = (value, defs) => {
|
|
3874
3867
|
if (isHex(value))
|
|
3875
3868
|
return normalizeHex(value);
|
|
@@ -13096,6 +13089,10 @@ var FILE_NAVIGATOR_ORDERS = ["tree", "recently-modified"];
|
|
|
13096
13089
|
var themeIds = themeDefinitions.map((theme) => theme.id);
|
|
13097
13090
|
var themeFooterLabels = uniqueFooterLabels(themeIds);
|
|
13098
13091
|
var houseOptions = defineOptions({
|
|
13092
|
+
autoHideSidebar: {
|
|
13093
|
+
type: "boolean",
|
|
13094
|
+
default: true
|
|
13095
|
+
},
|
|
13099
13096
|
wrap: {
|
|
13100
13097
|
type: "boolean",
|
|
13101
13098
|
default: false,
|
|
@@ -13178,6 +13175,7 @@ var parseShowList = (raw) => {
|
|
|
13178
13175
|
var DEFAULT_EXTENSIONS = [];
|
|
13179
13176
|
var DEFAULT_SHOW = "";
|
|
13180
13177
|
var KNOWN_FILE_KEYS = new Set([
|
|
13178
|
+
"autoHideSidebar",
|
|
13181
13179
|
"theme",
|
|
13182
13180
|
"tone",
|
|
13183
13181
|
"extensions",
|
|
@@ -13192,7 +13190,8 @@ var schema = Config.all({
|
|
|
13192
13190
|
extensions: Config.schema(Schema.String, "extensions"),
|
|
13193
13191
|
show: Config.schema(Schema.String, "show")
|
|
13194
13192
|
});
|
|
13195
|
-
var
|
|
13193
|
+
var fromUnknown = (root) => ConfigProvider.fromUnknown(root, { preserveEmptyStrings: true });
|
|
13194
|
+
var defaultsProvider = () => fromUnknown({
|
|
13196
13195
|
extensions: DEFAULT_EXTENSIONS.join(","),
|
|
13197
13196
|
show: DEFAULT_SHOW
|
|
13198
13197
|
});
|
|
@@ -13279,7 +13278,7 @@ var envProvider = (env) => {
|
|
|
13279
13278
|
entries.push(["extensions", extensions]);
|
|
13280
13279
|
if (show !== undefined)
|
|
13281
13280
|
entries.push(["show", show]);
|
|
13282
|
-
return
|
|
13281
|
+
return fromUnknown(Object.fromEntries(entries));
|
|
13283
13282
|
};
|
|
13284
13283
|
var cliProvider = (overrides) => {
|
|
13285
13284
|
const entries = [];
|
|
@@ -13287,7 +13286,7 @@ var cliProvider = (overrides) => {
|
|
|
13287
13286
|
entries.push(["extensions", overrides.extensions.join(",")]);
|
|
13288
13287
|
if (overrides.show !== null)
|
|
13289
13288
|
entries.push(["show", overrides.show.join(",")]);
|
|
13290
|
-
return
|
|
13289
|
+
return fromUnknown(Object.fromEntries(entries));
|
|
13291
13290
|
};
|
|
13292
13291
|
var defaultConfigPath = () => join3(process.env["XDG_CONFIG_HOME"] ?? join3(homedir(), ".config"), "house", "config.toml");
|
|
13293
13292
|
var formatConfigError = (err) => {
|
|
@@ -13302,6 +13301,7 @@ var formatConfigError = (err) => {
|
|
|
13302
13301
|
};
|
|
13303
13302
|
var loadConfig = (options = {}) => Effect2.gen(function* () {
|
|
13304
13303
|
const cli = options.cli ?? {
|
|
13304
|
+
autoHideSidebar: null,
|
|
13305
13305
|
theme: null,
|
|
13306
13306
|
tone: null,
|
|
13307
13307
|
extensions: null,
|
|
@@ -13324,6 +13324,7 @@ var loadConfig = (options = {}) => Effect2.gen(function* () {
|
|
|
13324
13324
|
}
|
|
13325
13325
|
const resolved = houseOptions.resolve({
|
|
13326
13326
|
cli: {
|
|
13327
|
+
autoHideSidebar: cli.autoHideSidebar,
|
|
13327
13328
|
wrap: cli.wrap,
|
|
13328
13329
|
width: cli.width,
|
|
13329
13330
|
theme: cli.theme,
|
|
@@ -13332,6 +13333,7 @@ var loadConfig = (options = {}) => Effect2.gen(function* () {
|
|
|
13332
13333
|
order: cli.order
|
|
13333
13334
|
},
|
|
13334
13335
|
env: {
|
|
13336
|
+
autoHideSidebar: env["HOUSE_AUTO_HIDE_SIDEBAR"],
|
|
13335
13337
|
wrap: env["HOUSE_WRAP"],
|
|
13336
13338
|
width: env["HOUSE_WIDTH"],
|
|
13337
13339
|
theme: env["HOUSE_THEME"],
|
|
@@ -13341,6 +13343,7 @@ var loadConfig = (options = {}) => Effect2.gen(function* () {
|
|
|
13341
13343
|
order: env["HOUSE_ORDER"]
|
|
13342
13344
|
},
|
|
13343
13345
|
file: {
|
|
13346
|
+
autoHideSidebar: fileData?.["autoHideSidebar"],
|
|
13344
13347
|
wrap: fileData?.["wrap"],
|
|
13345
13348
|
width: fileData?.["width"],
|
|
13346
13349
|
theme: fileData?.["theme"],
|
|
@@ -13370,6 +13373,7 @@ var loadConfig = (options = {}) => Effect2.gen(function* () {
|
|
|
13370
13373
|
return yield* Effect2.fail(new Error(`order: expected one of ${FILE_NAVIGATOR_ORDERS.join(", ")}, got ${JSON.stringify(order)}`));
|
|
13371
13374
|
}
|
|
13372
13375
|
return {
|
|
13376
|
+
autoHideSidebar: resolved.value.autoHideSidebar,
|
|
13373
13377
|
theme: resolved.value.theme,
|
|
13374
13378
|
tone,
|
|
13375
13379
|
defaultRoot,
|
|
@@ -13526,6 +13530,7 @@ var Browser = ({
|
|
|
13526
13530
|
initialQuery = "",
|
|
13527
13531
|
wrapWidth = 80,
|
|
13528
13532
|
initialWrap = false,
|
|
13533
|
+
initialAutoHideSidebar = true,
|
|
13529
13534
|
rootLabel = "current root",
|
|
13530
13535
|
discoveryStatus = null,
|
|
13531
13536
|
discoverySpinnerIntervalMs,
|
|
@@ -13540,6 +13545,7 @@ var Browser = ({
|
|
|
13540
13545
|
updateNotice = null,
|
|
13541
13546
|
updateNoticeTtlMs = 1e4,
|
|
13542
13547
|
disableFooterNoticeAutoClear = false,
|
|
13548
|
+
onNavigatorIdle,
|
|
13543
13549
|
onToggleAll,
|
|
13544
13550
|
startupFocus = null,
|
|
13545
13551
|
order = "recently-modified",
|
|
@@ -13559,6 +13565,7 @@ var Browser = ({
|
|
|
13559
13565
|
optionsSession.current = houseOptions.createSession({
|
|
13560
13566
|
...houseOptions.defaults,
|
|
13561
13567
|
wrap: initialWrap,
|
|
13568
|
+
autoHideSidebar: initialAutoHideSidebar,
|
|
13562
13569
|
width: wrapWidth,
|
|
13563
13570
|
theme: theme.id,
|
|
13564
13571
|
tone: theme.tone,
|
|
@@ -13705,11 +13712,36 @@ var Browser = ({
|
|
|
13705
13712
|
const paletteInputReadyRef = useRef3(false);
|
|
13706
13713
|
const promptInputReadyRef = useRef3(false);
|
|
13707
13714
|
const focusRef = useRef3(focus);
|
|
13715
|
+
const autoHideSidebar = optionsSession.current.get("autoHideSidebar");
|
|
13716
|
+
const openSelectedFile = () => {
|
|
13717
|
+
if (autoHideSidebar && navigator2.getSnapshot().selectedFile !== null)
|
|
13718
|
+
setShown(false);
|
|
13719
|
+
focusRef.current = "reader";
|
|
13720
|
+
setFocus("reader");
|
|
13721
|
+
};
|
|
13708
13722
|
const restoreFilterOnSidebarFocusRef = useRef3(startInFilter);
|
|
13709
13723
|
const [footerNotice, setFooterNoticeState] = useState4(null);
|
|
13710
13724
|
const pushFooterNotice = (text, ttlMs = 2000) => setFooterNoticeState({ text, ttlMs });
|
|
13711
13725
|
const serverRef = useRef3(initialPreviewServer);
|
|
13712
13726
|
const pendingSelectionPathRef = useRef3(null);
|
|
13727
|
+
const pendingSelectionMissingRef = useRef3(false);
|
|
13728
|
+
const clearPendingSelection = () => {
|
|
13729
|
+
pendingSelectionPathRef.current = null;
|
|
13730
|
+
pendingSelectionMissingRef.current = false;
|
|
13731
|
+
};
|
|
13732
|
+
const takePendingRestoreTarget = (files) => {
|
|
13733
|
+
const target = pendingSelectionPathRef.current;
|
|
13734
|
+
if (target === null)
|
|
13735
|
+
return null;
|
|
13736
|
+
const inList = files.some((file) => file.absolutePath === target);
|
|
13737
|
+
if (!inList) {
|
|
13738
|
+
pendingSelectionMissingRef.current = true;
|
|
13739
|
+
return null;
|
|
13740
|
+
}
|
|
13741
|
+
if (!pendingSelectionMissingRef.current)
|
|
13742
|
+
return null;
|
|
13743
|
+
return target;
|
|
13744
|
+
};
|
|
13713
13745
|
useLayoutEffect3(() => {
|
|
13714
13746
|
if (readerRootRef.current === root)
|
|
13715
13747
|
return;
|
|
@@ -13759,6 +13791,15 @@ var Browser = ({
|
|
|
13759
13791
|
useEffect4(() => {
|
|
13760
13792
|
focusRef.current = focus;
|
|
13761
13793
|
}, [focus]);
|
|
13794
|
+
const onNavigatorIdleRef = useRef3(onNavigatorIdle);
|
|
13795
|
+
onNavigatorIdleRef.current = onNavigatorIdle;
|
|
13796
|
+
const navigatorIdleNotifiedRef = useRef3(false);
|
|
13797
|
+
useEffect4(() => {
|
|
13798
|
+
if (navigatorIdleNotifiedRef.current || liveSnapshot.scanning)
|
|
13799
|
+
return;
|
|
13800
|
+
navigatorIdleNotifiedRef.current = true;
|
|
13801
|
+
onNavigatorIdleRef.current?.();
|
|
13802
|
+
}, [liveSnapshot.scanning]);
|
|
13762
13803
|
useEffect4(() => {
|
|
13763
13804
|
if (!updateNotice)
|
|
13764
13805
|
return;
|
|
@@ -13813,15 +13854,13 @@ var Browser = ({
|
|
|
13813
13854
|
};
|
|
13814
13855
|
const filterHasNoMatches = filterInput.length > 0 && displayedFiles.length === 0;
|
|
13815
13856
|
useEffect4(() => {
|
|
13816
|
-
const target =
|
|
13857
|
+
const target = takePendingRestoreTarget(displayedFiles);
|
|
13817
13858
|
if (target === null)
|
|
13818
13859
|
return;
|
|
13819
|
-
|
|
13820
|
-
|
|
13821
|
-
|
|
13822
|
-
|
|
13823
|
-
pendingSelectionPathRef.current = null;
|
|
13824
|
-
}
|
|
13860
|
+
const snapshot = navigator2.selectPath(target);
|
|
13861
|
+
if (snapshot.selectedFile?.absolutePath !== target)
|
|
13862
|
+
return;
|
|
13863
|
+
clearPendingSelection();
|
|
13825
13864
|
}, [displayedFiles, liveSnapshot.files]);
|
|
13826
13865
|
useEffect4(() => {
|
|
13827
13866
|
if (liveSnapshot.scanning || initialIndexRef.current === 0)
|
|
@@ -14167,18 +14206,19 @@ var Browser = ({
|
|
|
14167
14206
|
paletteOpen,
|
|
14168
14207
|
wrapEnabled,
|
|
14169
14208
|
setFocus,
|
|
14209
|
+
openSelectedFile,
|
|
14170
14210
|
moveSelectionBy: (delta) => {
|
|
14171
|
-
|
|
14211
|
+
clearPendingSelection();
|
|
14172
14212
|
newFileEditPathRef.current = null;
|
|
14173
14213
|
navigator2.moveBy(delta);
|
|
14174
14214
|
},
|
|
14175
14215
|
selectFirst: () => {
|
|
14176
|
-
|
|
14216
|
+
clearPendingSelection();
|
|
14177
14217
|
newFileEditPathRef.current = null;
|
|
14178
14218
|
navigator2.selectFirst();
|
|
14179
14219
|
},
|
|
14180
14220
|
selectLast: () => {
|
|
14181
|
-
|
|
14221
|
+
clearPendingSelection();
|
|
14182
14222
|
newFileEditPathRef.current = null;
|
|
14183
14223
|
navigator2.selectLast();
|
|
14184
14224
|
},
|
|
@@ -14235,6 +14275,7 @@ var Browser = ({
|
|
|
14235
14275
|
const current = navigator2.getSnapshot().selectedFile;
|
|
14236
14276
|
if (pendingSelectionPathRef.current === null && current) {
|
|
14237
14277
|
pendingSelectionPathRef.current = current.absolutePath;
|
|
14278
|
+
pendingSelectionMissingRef.current = false;
|
|
14238
14279
|
}
|
|
14239
14280
|
onToggleAll?.();
|
|
14240
14281
|
},
|
|
@@ -14378,6 +14419,10 @@ var Browser = ({
|
|
|
14378
14419
|
key.preventDefault();
|
|
14379
14420
|
return;
|
|
14380
14421
|
}
|
|
14422
|
+
if (key.ctrl && !key.meta && key.name === "c") {
|
|
14423
|
+
key.preventDefault();
|
|
14424
|
+
return;
|
|
14425
|
+
}
|
|
14381
14426
|
if (!promptInputReadyRef.current) {
|
|
14382
14427
|
if (key.name === "backspace" || key.name === "delete") {
|
|
14383
14428
|
if (promptInputRef.current.length === 0)
|
|
@@ -14402,8 +14447,7 @@ var Browser = ({
|
|
|
14402
14447
|
filterOpenRef.current = false;
|
|
14403
14448
|
setFilterOpen(false);
|
|
14404
14449
|
if (effectiveCommit) {
|
|
14405
|
-
|
|
14406
|
-
setFocus("reader");
|
|
14450
|
+
openSelectedFile();
|
|
14407
14451
|
} else {
|
|
14408
14452
|
const nextFocus = shown ? "sidebar" : "reader";
|
|
14409
14453
|
focusRef.current = nextFocus;
|
|
@@ -14587,9 +14631,9 @@ var Browser = ({
|
|
|
14587
14631
|
if (!handle)
|
|
14588
14632
|
return;
|
|
14589
14633
|
const next = handle.getSnapshot();
|
|
14590
|
-
const target =
|
|
14591
|
-
if (target
|
|
14592
|
-
|
|
14634
|
+
const target = takePendingRestoreTarget(next.filteredFiles);
|
|
14635
|
+
if (target !== null) {
|
|
14636
|
+
clearPendingSelection();
|
|
14593
14637
|
setNavigatorSnapshot(handle.selectPath(target));
|
|
14594
14638
|
return;
|
|
14595
14639
|
}
|
|
@@ -14743,7 +14787,7 @@ var Browser = ({
|
|
|
14743
14787
|
|
|
14744
14788
|
// src/cli/argv.ts
|
|
14745
14789
|
import { Command } from "commander";
|
|
14746
|
-
var createProgram = () => new Command().allowUnknownOption(true).allowExcessArguments(true).exitOverride().helpOption(false).option("--theme [id]").option("--tone [mode]").option("--width [N]").option("--wrap").option("--no-wrap").option("--serve").option("--port [N]").option("--config-path").option("--no-update-check").option("--ext [list]").option("--focus [mode]").option("--order [mode]").option("--show [list]").option("--root [dir]").option("-h, --help").option("-v, --version").argument("[path]");
|
|
14790
|
+
var createProgram = () => new Command().allowUnknownOption(true).allowExcessArguments(true).exitOverride().helpOption(false).option("--theme [id]").option("--tone [mode]").option("--width [N]").option("--wrap").option("--no-wrap").option("--auto-hide-sidebar").option("--no-auto-hide-sidebar").option("--serve").option("--port [N]").option("--config-path").option("--no-update-check").option("--ext [list]").option("--focus [mode]").option("--order [mode]").option("--show [list]").option("--root [dir]").option("-h, --help").option("-v, --version").argument("[path]");
|
|
14747
14791
|
var VALUE_FLAGS = new Set([
|
|
14748
14792
|
"--theme",
|
|
14749
14793
|
"--tone",
|
|
@@ -14762,6 +14806,8 @@ var BOOLEAN_FLAGS = new Set([
|
|
|
14762
14806
|
"--no-update-check",
|
|
14763
14807
|
"--wrap",
|
|
14764
14808
|
"--no-wrap",
|
|
14809
|
+
"--auto-hide-sidebar",
|
|
14810
|
+
"--no-auto-hide-sidebar",
|
|
14765
14811
|
"--help",
|
|
14766
14812
|
"-h",
|
|
14767
14813
|
"--version",
|
|
@@ -14792,6 +14838,8 @@ var parseArgv = (argv) => {
|
|
|
14792
14838
|
const stringOrNull = (value) => typeof value === "string" ? value : null;
|
|
14793
14839
|
const hasWrap = argv.includes("--wrap");
|
|
14794
14840
|
const hasNoWrap = argv.includes("--no-wrap");
|
|
14841
|
+
const hasAutoHideSidebar = argv.includes("--auto-hide-sidebar");
|
|
14842
|
+
const hasNoAutoHideSidebar = argv.includes("--no-auto-hide-sidebar");
|
|
14795
14843
|
return {
|
|
14796
14844
|
path: typeof pathArg === "string" ? pathArg : null,
|
|
14797
14845
|
root: stringOrNull(opts["root"]),
|
|
@@ -14800,6 +14848,8 @@ var parseArgv = (argv) => {
|
|
|
14800
14848
|
width: stringOrNull(opts["width"]),
|
|
14801
14849
|
wrap: hasWrap ? true : hasNoWrap ? false : null,
|
|
14802
14850
|
wrapConflict: hasWrap && hasNoWrap,
|
|
14851
|
+
autoHideSidebar: hasAutoHideSidebar ? true : hasNoAutoHideSidebar ? false : null,
|
|
14852
|
+
autoHideSidebarConflict: hasAutoHideSidebar && hasNoAutoHideSidebar,
|
|
14803
14853
|
serve: opts["serve"] === true,
|
|
14804
14854
|
port: stringOrNull(opts["port"]),
|
|
14805
14855
|
help: opts["help"] === true,
|
|
@@ -14825,6 +14875,8 @@ options:
|
|
|
14825
14875
|
--width <N> reader wrap width used when wrapping is enabled (default: 80)
|
|
14826
14876
|
--wrap start with reader wrapping enabled
|
|
14827
14877
|
--no-wrap start with reader wrapping disabled
|
|
14878
|
+
--auto-hide-sidebar hide the sidebar after opening a file (default)
|
|
14879
|
+
--no-auto-hide-sidebar keep the sidebar visible after opening a file
|
|
14828
14880
|
--show <list> reveal normally-skipped entries; comma-separated subset of:
|
|
14829
14881
|
hidden, gitignored. Use --show "" to clear.
|
|
14830
14882
|
--root <dir> discovery root to walk (overrides defaultRoot config/env)
|
|
@@ -14845,8 +14897,8 @@ examples:
|
|
|
14845
14897
|
|
|
14846
14898
|
configuration:
|
|
14847
14899
|
file: $XDG_CONFIG_HOME/house/config.toml (default ~/.config/house/config.toml)
|
|
14848
|
-
keys: theme, tone, width, wrap, extensions, show, focus, defaultRoot, order
|
|
14849
|
-
env: HOUSE_THEME, HOUSE_TONE, HOUSE_WIDTH, HOUSE_WRAP, HOUSE_EXTENSIONS, HOUSE_SHOW, HOUSE_FOCUS, HOUSE_DEFAULT_ROOT, HOUSE_ORDER
|
|
14900
|
+
keys: theme, tone, width, wrap, autoHideSidebar, extensions, show, focus, defaultRoot, order
|
|
14901
|
+
env: HOUSE_THEME, HOUSE_TONE, HOUSE_WIDTH, HOUSE_WRAP, HOUSE_AUTO_HIDE_SIDEBAR, HOUSE_EXTENSIONS, HOUSE_SHOW, HOUSE_FOCUS, HOUSE_DEFAULT_ROOT, HOUSE_ORDER
|
|
14850
14902
|
precedence (high \u2192 low): flags \u2192 env \u2192 file \u2192 defaults`;
|
|
14851
14903
|
|
|
14852
14904
|
// src/cli/fast-exit.ts
|
|
@@ -14860,6 +14912,10 @@ var parseAndHandleFastExit = (argv) => {
|
|
|
14860
14912
|
console.error("house: --wrap and --no-wrap cannot be used together");
|
|
14861
14913
|
process.exit(2);
|
|
14862
14914
|
}
|
|
14915
|
+
if (args.autoHideSidebarConflict) {
|
|
14916
|
+
console.error("house: --auto-hide-sidebar and --no-auto-hide-sidebar cannot be used together");
|
|
14917
|
+
process.exit(2);
|
|
14918
|
+
}
|
|
14863
14919
|
if (argv.includes("--width") && args.width === null) {
|
|
14864
14920
|
console.error("house: --width requires a positive integer");
|
|
14865
14921
|
process.exit(2);
|
|
@@ -15185,6 +15241,7 @@ var DiscoverShell = ({
|
|
|
15185
15241
|
extensions,
|
|
15186
15242
|
wrapWidth,
|
|
15187
15243
|
initialWrap,
|
|
15244
|
+
initialAutoHideSidebar,
|
|
15188
15245
|
startupFocus,
|
|
15189
15246
|
order = "recently-modified"
|
|
15190
15247
|
}) => {
|
|
@@ -15197,6 +15254,7 @@ var DiscoverShell = ({
|
|
|
15197
15254
|
initialQuery,
|
|
15198
15255
|
wrapWidth,
|
|
15199
15256
|
initialWrap,
|
|
15257
|
+
initialAutoHideSidebar,
|
|
15200
15258
|
rootLabel,
|
|
15201
15259
|
startupFocus,
|
|
15202
15260
|
order,
|
|
@@ -15252,7 +15310,8 @@ async function main(argv = Bun.argv.slice(2)) {
|
|
|
15252
15310
|
}
|
|
15253
15311
|
return n;
|
|
15254
15312
|
})(),
|
|
15255
|
-
wrap: args.wrap
|
|
15313
|
+
wrap: args.wrap,
|
|
15314
|
+
autoHideSidebar: args.autoHideSidebar
|
|
15256
15315
|
}
|
|
15257
15316
|
})).catch((err) => {
|
|
15258
15317
|
console.error(`house: ${formatConfigError(err)}`);
|
|
@@ -15267,6 +15326,7 @@ async function main(argv = Bun.argv.slice(2)) {
|
|
|
15267
15326
|
defaultRoot,
|
|
15268
15327
|
width: wrapWidth,
|
|
15269
15328
|
wrap: initialWrap,
|
|
15329
|
+
autoHideSidebar: initialAutoHideSidebar,
|
|
15270
15330
|
order
|
|
15271
15331
|
} = config;
|
|
15272
15332
|
const themeDef = getThemeDefinition(themeId);
|
|
@@ -15322,6 +15382,7 @@ async function main(argv = Bun.argv.slice(2)) {
|
|
|
15322
15382
|
tone,
|
|
15323
15383
|
wrapWidth,
|
|
15324
15384
|
initialWrap,
|
|
15385
|
+
initialAutoHideSidebar,
|
|
15325
15386
|
show,
|
|
15326
15387
|
extensions,
|
|
15327
15388
|
startupFocus,
|
|
@@ -15339,6 +15400,7 @@ async function runTui({
|
|
|
15339
15400
|
tone,
|
|
15340
15401
|
wrapWidth,
|
|
15341
15402
|
initialWrap,
|
|
15403
|
+
initialAutoHideSidebar,
|
|
15342
15404
|
show,
|
|
15343
15405
|
extensions,
|
|
15344
15406
|
startupFocus,
|
|
@@ -15380,6 +15442,7 @@ async function runTui({
|
|
|
15380
15442
|
extensions,
|
|
15381
15443
|
wrapWidth,
|
|
15382
15444
|
initialWrap,
|
|
15445
|
+
initialAutoHideSidebar,
|
|
15383
15446
|
startupFocus,
|
|
15384
15447
|
order
|
|
15385
15448
|
}, undefined, false, undefined, this)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@carlesandres/house",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "TUI-first markdown reader on opentui",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -62,21 +62,21 @@
|
|
|
62
62
|
"version:set": "bun run dev/set-version.ts"
|
|
63
63
|
},
|
|
64
64
|
"optionalDependencies": {
|
|
65
|
-
"@carlesandres/house-darwin-arm64": "0.
|
|
66
|
-
"@carlesandres/house-darwin-x64": "0.
|
|
67
|
-
"@carlesandres/house-linux-arm64": "0.
|
|
68
|
-
"@carlesandres/house-linux-x64": "0.
|
|
65
|
+
"@carlesandres/house-darwin-arm64": "0.9.0",
|
|
66
|
+
"@carlesandres/house-darwin-x64": "0.9.0",
|
|
67
|
+
"@carlesandres/house-linux-arm64": "0.9.0",
|
|
68
|
+
"@carlesandres/house-linux-x64": "0.9.0"
|
|
69
69
|
},
|
|
70
70
|
"dependencies": {
|
|
71
|
-
"@effect/atom-react": "4.0.0-beta.
|
|
72
|
-
"@opentui/core": "0.
|
|
73
|
-
"@opentui/react": "0.
|
|
71
|
+
"@effect/atom-react": "4.0.0-beta.107",
|
|
72
|
+
"@opentui/core": "0.5.9",
|
|
73
|
+
"@opentui/react": "0.5.9",
|
|
74
74
|
"@parcel/watcher": "2.6.0",
|
|
75
75
|
"commander": "^14.0.3",
|
|
76
|
-
"effect": "4.0.0-beta.
|
|
76
|
+
"effect": "4.0.0-beta.107",
|
|
77
77
|
"ignore": "^7.0.5",
|
|
78
78
|
"marked": "^18.0.4",
|
|
79
|
-
"react": "19.2.
|
|
79
|
+
"react": "19.2.8",
|
|
80
80
|
"scheduler": "0.27.0",
|
|
81
81
|
"string-width": "7.2.0",
|
|
82
82
|
"web-tree-sitter": "0.25.10"
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"devDependencies": {
|
|
85
85
|
"@effect/language-service": "0.86.2",
|
|
86
86
|
"@types/bun": "1.3.14",
|
|
87
|
-
"@types/react": "19.2.
|
|
87
|
+
"@types/react": "19.2.18",
|
|
88
88
|
"emulate": "0.9.0",
|
|
89
89
|
"oxfmt": "0.51.0",
|
|
90
90
|
"oxlint": "1.66.0",
|