@youtyan/code-viewer 0.2.9 → 0.2.10
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/README.md +11 -7
- package/dist/code-viewer.js +86 -21
- package/package.json +1 -1
- package/web/app.js +89 -5
- package/web/index.html +11 -0
- package/web/style.css +14 -0
package/README.md
CHANGED
|
@@ -115,7 +115,9 @@ rendered, and the page includes controls to copy the full file or reopen it in
|
|
|
115
115
|
the full non-virtual view.
|
|
116
116
|
|
|
117
117
|
The worktree is watched and changes are pushed to every open tab over SSE so
|
|
118
|
-
files reload as you edit.
|
|
118
|
+
files reload as you edit. The directory watcher is capped at 1024 directories
|
|
119
|
+
by default and can be tuned from Viewer Settings → **File change watcher**
|
|
120
|
+
(range slider + numeric input, 16–65536); when the cap is hit the viewer
|
|
119
121
|
shows a banner so reloads are not silently missed.
|
|
120
122
|
|
|
121
123
|
Large repositories load folder children on demand. The sidebar remembers which
|
|
@@ -129,13 +131,15 @@ views remain read-only. Open **Viewer Settings** in the header to toggle
|
|
|
129
131
|
uploads off, edit the directories to skip while browsing/searching, and hide
|
|
130
132
|
files or directory names completely.
|
|
131
133
|
|
|
132
|
-
Scope settings control
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
Scope settings control directory exclusions shared by the sidebar, Ctrl+K file
|
|
135
|
+
palette, Ctrl+G grep palette, the Datastores browser, and the file change
|
|
136
|
+
watcher — the same list applies to all five. Everything you change in Viewer
|
|
137
|
+
Settings is saved on the server under `.code-viewer/settings.json` (no
|
|
138
|
+
separate project-level config file). `.DS_Store` and a broad set of
|
|
136
139
|
build/cache directories (`node_modules`, `dist`, `build`, `.next`, `.turbo`,
|
|
137
|
-
`.venv`, …) are hidden by
|
|
138
|
-
|
|
140
|
+
`.parcel-cache`, `.vite`, `.angular`, `.dart_tool`, `.venv`, …) are hidden by
|
|
141
|
+
default. Pass `--scope-omit-dir <name>` (repeatable) to override the omit
|
|
142
|
+
list on the command line for one session.
|
|
139
143
|
|
|
140
144
|
The viewer keeps its per-project state under `.code-viewer/` at the repository
|
|
141
145
|
root:
|
package/dist/code-viewer.js
CHANGED
|
@@ -1514,6 +1514,7 @@ var init_git = __esm(() => {
|
|
|
1514
1514
|
init_runtime();
|
|
1515
1515
|
DEFAULT_WORKTREE_OMIT_DIR_NAMES = [
|
|
1516
1516
|
"node_modules",
|
|
1517
|
+
"bower_components",
|
|
1517
1518
|
".venv",
|
|
1518
1519
|
"venv",
|
|
1519
1520
|
".next",
|
|
@@ -1521,6 +1522,11 @@ var init_git = __esm(() => {
|
|
|
1521
1522
|
".svelte-kit",
|
|
1522
1523
|
".astro",
|
|
1523
1524
|
".vercel",
|
|
1525
|
+
".angular",
|
|
1526
|
+
".docusaurus",
|
|
1527
|
+
".expo",
|
|
1528
|
+
".dart_tool",
|
|
1529
|
+
".serverless",
|
|
1524
1530
|
"dist",
|
|
1525
1531
|
"build",
|
|
1526
1532
|
"out",
|
|
@@ -1528,6 +1534,9 @@ var init_git = __esm(() => {
|
|
|
1528
1534
|
".gradle",
|
|
1529
1535
|
".pnpm-store",
|
|
1530
1536
|
".turbo",
|
|
1537
|
+
".parcel-cache",
|
|
1538
|
+
".vite",
|
|
1539
|
+
".webpack",
|
|
1531
1540
|
"__pycache__",
|
|
1532
1541
|
".pytest_cache",
|
|
1533
1542
|
".tox",
|
|
@@ -1537,6 +1546,7 @@ var init_git = __esm(() => {
|
|
|
1537
1546
|
"vendor",
|
|
1538
1547
|
".cache",
|
|
1539
1548
|
"coverage",
|
|
1549
|
+
".nyc_output",
|
|
1540
1550
|
"tmp",
|
|
1541
1551
|
"log",
|
|
1542
1552
|
"storage",
|
|
@@ -4410,7 +4420,7 @@ function startWorktreeUpdateWatch(options) {
|
|
|
4410
4420
|
watchDirectory(options.root, true);
|
|
4411
4421
|
return { started: watchers.size > 0, close: closeAll };
|
|
4412
4422
|
}
|
|
4413
|
-
var DEFAULT_WORKTREE_WATCH_DIRECTORY_LIMIT =
|
|
4423
|
+
var DEFAULT_WORKTREE_WATCH_DIRECTORY_LIMIT = 1024, MIN_WORKTREE_WATCH_DIRECTORY_LIMIT = 1, MAX_WORKTREE_WATCH_DIRECTORY_LIMIT = 65536;
|
|
4414
4424
|
var init_worktree_watcher = __esm(() => {
|
|
4415
4425
|
init_search();
|
|
4416
4426
|
});
|
|
@@ -11382,6 +11392,7 @@ Examples:
|
|
|
11382
11392
|
if (scopeOmitDirCliOverride) {
|
|
11383
11393
|
scopeOmitDirNames = scopeOmitDirCliOverride;
|
|
11384
11394
|
}
|
|
11395
|
+
scopeWatchLimit = worktreeWatchDirectoryLimitFromEnv();
|
|
11385
11396
|
}
|
|
11386
11397
|
function warnIfLegacyConfigPresent() {
|
|
11387
11398
|
try {
|
|
@@ -11391,6 +11402,9 @@ function warnIfLegacyConfigPresent() {
|
|
|
11391
11402
|
} catch {}
|
|
11392
11403
|
}
|
|
11393
11404
|
function applyPersistedSettings(state) {
|
|
11405
|
+
const prevOmit = scopeOmitDirNames;
|
|
11406
|
+
const prevExclude = scopeExcludeNames;
|
|
11407
|
+
const prevWatchLimit = scopeWatchLimit;
|
|
11394
11408
|
if (!scopeOmitDirCliOverride && Array.isArray(state.scopeOmitDirs) && state.scopeOmitDirs.length > 0) {
|
|
11395
11409
|
scopeOmitDirNames = state.scopeOmitDirs;
|
|
11396
11410
|
} else if (!scopeOmitDirCliOverride) {
|
|
@@ -11401,7 +11415,26 @@ function applyPersistedSettings(state) {
|
|
|
11401
11415
|
} else {
|
|
11402
11416
|
scopeExcludeNames = DEFAULT_EXCLUDE_NAMES;
|
|
11403
11417
|
}
|
|
11418
|
+
if (state.scopeWatchLimit != null) {
|
|
11419
|
+
scopeWatchLimit = normalizeScopeWatchLimit(state.scopeWatchLimit);
|
|
11420
|
+
}
|
|
11404
11421
|
uploadEnabled = state.uploadEnabled !== false;
|
|
11422
|
+
if (prevOmit !== scopeOmitDirNames || prevExclude !== scopeExcludeNames || prevWatchLimit !== scopeWatchLimit) {
|
|
11423
|
+
restartWorktreeWatch();
|
|
11424
|
+
}
|
|
11425
|
+
}
|
|
11426
|
+
function normalizeScopeWatchLimit(value) {
|
|
11427
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
11428
|
+
return DEFAULT_WORKTREE_WATCH_DIRECTORY_LIMIT;
|
|
11429
|
+
}
|
|
11430
|
+
const floored = Math.floor(value);
|
|
11431
|
+
if (floored < MIN_WORKTREE_WATCH_DIRECTORY_LIMIT) {
|
|
11432
|
+
return MIN_WORKTREE_WATCH_DIRECTORY_LIMIT;
|
|
11433
|
+
}
|
|
11434
|
+
if (floored > MAX_WORKTREE_WATCH_DIRECTORY_LIMIT) {
|
|
11435
|
+
return MAX_WORKTREE_WATCH_DIRECTORY_LIMIT;
|
|
11436
|
+
}
|
|
11437
|
+
return floored;
|
|
11405
11438
|
}
|
|
11406
11439
|
function json2(data, init = {}) {
|
|
11407
11440
|
return new Response(JSON.stringify(data), {
|
|
@@ -11883,7 +11916,11 @@ function handleSettings() {
|
|
|
11883
11916
|
omit_dirs_built_in: DEFAULT_WORKTREE_OMIT_DIR_NAMES,
|
|
11884
11917
|
exclude_names_effective: scopeExcludeNames,
|
|
11885
11918
|
exclude_names_built_in: DEFAULT_EXCLUDE_NAMES,
|
|
11886
|
-
max_entries: WORKTREE_RECURSIVE_ENTRY_LIMIT
|
|
11919
|
+
max_entries: WORKTREE_RECURSIVE_ENTRY_LIMIT,
|
|
11920
|
+
watch_limit_effective: scopeWatchLimit,
|
|
11921
|
+
watch_limit_default: DEFAULT_WORKTREE_WATCH_DIRECTORY_LIMIT,
|
|
11922
|
+
watch_limit_min: MIN_WORKTREE_WATCH_DIRECTORY_LIMIT,
|
|
11923
|
+
watch_limit_max: MAX_WORKTREE_WATCH_DIRECTORY_LIMIT
|
|
11887
11924
|
}
|
|
11888
11925
|
});
|
|
11889
11926
|
}
|
|
@@ -11892,7 +11929,14 @@ function worktreeWatchDirectoryLimitFromEnv() {
|
|
|
11892
11929
|
if (!raw)
|
|
11893
11930
|
return DEFAULT_WORKTREE_WATCH_DIRECTORY_LIMIT;
|
|
11894
11931
|
const parsed = Number(raw);
|
|
11895
|
-
|
|
11932
|
+
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
11933
|
+
return DEFAULT_WORKTREE_WATCH_DIRECTORY_LIMIT;
|
|
11934
|
+
const floored = Math.floor(parsed);
|
|
11935
|
+
if (floored < MIN_WORKTREE_WATCH_DIRECTORY_LIMIT)
|
|
11936
|
+
return MIN_WORKTREE_WATCH_DIRECTORY_LIMIT;
|
|
11937
|
+
if (floored > MAX_WORKTREE_WATCH_DIRECTORY_LIMIT)
|
|
11938
|
+
return MAX_WORKTREE_WATCH_DIRECTORY_LIMIT;
|
|
11939
|
+
return floored;
|
|
11896
11940
|
}
|
|
11897
11941
|
function handleFiles2(url) {
|
|
11898
11942
|
const target = url.searchParams.get("ref") || url.searchParams.get("target") || "worktree";
|
|
@@ -13033,7 +13077,43 @@ async function shutdown(exitCode = 0) {
|
|
|
13033
13077
|
}
|
|
13034
13078
|
process.exit(exitCode);
|
|
13035
13079
|
}
|
|
13036
|
-
|
|
13080
|
+
function startScopedWorktreeWatch() {
|
|
13081
|
+
watchLimitReached = null;
|
|
13082
|
+
return startWorktreeUpdateWatch({
|
|
13083
|
+
root: cwd,
|
|
13084
|
+
omitDirNames: scopeOmitDirNames,
|
|
13085
|
+
excludeNames: scopeExcludeNames,
|
|
13086
|
+
watch,
|
|
13087
|
+
initialScanMode: "async",
|
|
13088
|
+
maxWatchedDirectories: scopeWatchLimit,
|
|
13089
|
+
onUpdate: triggerUpdate,
|
|
13090
|
+
onWatchLimit: (limit) => {
|
|
13091
|
+
watchLimitReached = limit;
|
|
13092
|
+
sendSse("watch-limit", String(limit));
|
|
13093
|
+
},
|
|
13094
|
+
onError: (error) => {
|
|
13095
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
13096
|
+
console.warn(`code-viewer worktree watch skipped: ${message}`);
|
|
13097
|
+
}
|
|
13098
|
+
});
|
|
13099
|
+
}
|
|
13100
|
+
function restartWorktreeWatch() {
|
|
13101
|
+
try {
|
|
13102
|
+
if (shuttingDown)
|
|
13103
|
+
return;
|
|
13104
|
+
if (!worktreeWatch)
|
|
13105
|
+
return;
|
|
13106
|
+
} catch {
|
|
13107
|
+
return;
|
|
13108
|
+
}
|
|
13109
|
+
try {
|
|
13110
|
+
worktreeWatch.close();
|
|
13111
|
+
} catch (error) {
|
|
13112
|
+
console.warn(`code-viewer worktree watch restart close skipped: ${String(error)}`);
|
|
13113
|
+
}
|
|
13114
|
+
worktreeWatch = startScopedWorktreeWatch();
|
|
13115
|
+
}
|
|
13116
|
+
var WEB_ROOT, VERSION, DEFAULT_ARGS, PREVIEW_HUNKS_DEFAULT = 3, PREVIEW_LINES_DEFAULT = 1200, WATCHED_ASSET_FILES, SIZE_SMALL = 2000, SIZE_MEDIUM = 8000, SIZE_LARGE = 20000, LINE_INDEX_MIN_START = 1e4, LINE_INDEX_MAX_FILE_BYTES, BLOB_LINE_CACHE_MAX_BYTES, MAX_UPLOAD_FILE_BYTES, MAX_UPLOAD_TOTAL_BYTES, MAX_UPLOAD_BODY_BYTES, MAX_UPLOAD_FILES = 50, SAFE_UPLOAD_EXTENSIONS, generation = 1, cwd, cliArgs, listenPort = 0, openAfterStart = false, scopeOmitDirNames, scopeOmitDirCliOverride = null, scopeExcludeNames, scopeWatchLimit, uploadEnabled = true, rgAvailableCache = null, enc, sseClients, sseKeepalives, fileCache, metaCache, fileListCache, lineIndexCache, blobLineIndexCache, blobBytesCache, blobLineCacheBytes = 0, isCodeViewerInternalPath, watchLimitReached = null, server, worktreeWatch = null, shuttingDown = false;
|
|
13037
13117
|
var init_preview = __esm(async () => {
|
|
13038
13118
|
init_routes();
|
|
13039
13119
|
init_annotations();
|
|
@@ -13096,6 +13176,7 @@ var init_preview = __esm(async () => {
|
|
|
13096
13176
|
cliArgs = DEFAULT_ARGS;
|
|
13097
13177
|
scopeOmitDirNames = DEFAULT_WORKTREE_OMIT_DIR_NAMES;
|
|
13098
13178
|
scopeExcludeNames = DEFAULT_EXCLUDE_NAMES;
|
|
13179
|
+
scopeWatchLimit = DEFAULT_WORKTREE_WATCH_DIRECTORY_LIMIT;
|
|
13099
13180
|
enc = new TextEncoder;
|
|
13100
13181
|
sseClients = new Set;
|
|
13101
13182
|
sseKeepalives = new Map;
|
|
@@ -13248,23 +13329,7 @@ data: ${watchLimitReached}
|
|
|
13248
13329
|
watch,
|
|
13249
13330
|
sendReload: () => sendSse("reload")
|
|
13250
13331
|
});
|
|
13251
|
-
worktreeWatch =
|
|
13252
|
-
root: cwd,
|
|
13253
|
-
omitDirNames: scopeOmitDirNames,
|
|
13254
|
-
excludeNames: scopeExcludeNames,
|
|
13255
|
-
watch,
|
|
13256
|
-
initialScanMode: "async",
|
|
13257
|
-
maxWatchedDirectories: worktreeWatchDirectoryLimitFromEnv(),
|
|
13258
|
-
onUpdate: triggerUpdate,
|
|
13259
|
-
onWatchLimit: (limit) => {
|
|
13260
|
-
watchLimitReached = limit;
|
|
13261
|
-
sendSse("watch-limit", String(limit));
|
|
13262
|
-
},
|
|
13263
|
-
onError: (error) => {
|
|
13264
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
13265
|
-
console.warn(`code-viewer worktree watch skipped: ${message}`);
|
|
13266
|
-
}
|
|
13267
|
-
});
|
|
13332
|
+
worktreeWatch = startScopedWorktreeWatch();
|
|
13268
13333
|
console.log(`GDP_LISTEN_URL=http://127.0.0.1:${server.port}/`);
|
|
13269
13334
|
console.log(`git-diff-preview serving ${cwd}`);
|
|
13270
13335
|
});
|
package/package.json
CHANGED
package/web/app.js
CHANGED
|
@@ -25460,6 +25460,9 @@ code-viewer query clear --db app.db`
|
|
|
25460
25460
|
let highlightLoadPromise = null;
|
|
25461
25461
|
let SERVER_SCOPE_OMIT_DIRS_DEFAULT = [];
|
|
25462
25462
|
let SERVER_SCOPE_EXCLUDE_NAMES_DEFAULT = [];
|
|
25463
|
+
let SERVER_SCOPE_WATCH_LIMIT_DEFAULT = 1024;
|
|
25464
|
+
let SERVER_SCOPE_WATCH_LIMIT_MIN = 16;
|
|
25465
|
+
let SERVER_SCOPE_WATCH_LIMIT_MAX = 65536;
|
|
25463
25466
|
const UNDO_STACK = [];
|
|
25464
25467
|
let PENDING_G_SCOPE = null;
|
|
25465
25468
|
let PENDING_G_UNTIL = 0;
|
|
@@ -25826,6 +25829,12 @@ code-viewer query clear --db app.db`
|
|
|
25826
25829
|
}
|
|
25827
25830
|
SERVER_SCOPE_OMIT_DIRS_DEFAULT = normalizeScopeOmitDirs(settings.scope.omit_dirs_effective);
|
|
25828
25831
|
SERVER_SCOPE_EXCLUDE_NAMES_DEFAULT = normalizeScopeExcludeNames(settings.scope.exclude_names_effective);
|
|
25832
|
+
if (typeof settings.scope.watch_limit_default === "number")
|
|
25833
|
+
SERVER_SCOPE_WATCH_LIMIT_DEFAULT = settings.scope.watch_limit_default;
|
|
25834
|
+
if (typeof settings.scope.watch_limit_min === "number")
|
|
25835
|
+
SERVER_SCOPE_WATCH_LIMIT_MIN = settings.scope.watch_limit_min;
|
|
25836
|
+
if (typeof settings.scope.watch_limit_max === "number")
|
|
25837
|
+
SERVER_SCOPE_WATCH_LIMIT_MAX = settings.scope.watch_limit_max;
|
|
25829
25838
|
return settings;
|
|
25830
25839
|
} catch {
|
|
25831
25840
|
return null;
|
|
@@ -26184,15 +26193,20 @@ code-viewer query clear --db app.db`
|
|
|
26184
26193
|
displaySource: "Applies to all projects in this browser.",
|
|
26185
26194
|
excludedDirectories: "Excluded directories",
|
|
26186
26195
|
omitDirs: "Skip these directory names while browsing and searching",
|
|
26196
|
+
omitDirsHelp: "Reads no contents inside these directories. Applies to the sidebar (Files), Ctrl+K (file search), Ctrl+G (grep), Datastores, and the file change watcher.",
|
|
26187
26197
|
excludeNames: "Hide these file or directory names completely",
|
|
26198
|
+
excludeNamesHelp: "Removes matching files or directories from the sidebar, search, and grep results entirely. Unlike Skip, the names themselves disappear from the UI.",
|
|
26188
26199
|
reset: "Restore defaults",
|
|
26189
26200
|
autosaveNote: "Changes save automatically.",
|
|
26190
|
-
scopeSource: (project, source) => `Saved for project "${project}" in this browser. Source: ${source}. Used by
|
|
26201
|
+
scopeSource: (project, source) => `Saved for project "${project}" in this browser. Source: ${source}. Used by the sidebar, Ctrl+K, Ctrl+G, Datastores, and the file change watcher. Restore defaults removes the browser override.`,
|
|
26191
26202
|
browserOverride: "Browser override",
|
|
26192
26203
|
serverDefault: "Server default",
|
|
26193
26204
|
uploadsTitle: "Uploads",
|
|
26194
26205
|
uploadEnabledLabel: "Allow file uploads into worktree folders",
|
|
26195
|
-
uploadEnabledHelp: "Disable to make the worktree read-only for everyone using this server."
|
|
26206
|
+
uploadEnabledHelp: "Disable to make the worktree read-only for everyone using this server.",
|
|
26207
|
+
watchTitle: "File change watcher",
|
|
26208
|
+
watchLimit: "Maximum directories to watch",
|
|
26209
|
+
watchLimitHelp: (defaultLimit) => `Higher values reduce missed updates in deep trees at the cost of file handles. Combine with the Skip list above to keep heavy folders (node_modules, .git, dist...) out of the watch budget. Default: ${defaultLimit}.`
|
|
26196
26210
|
},
|
|
26197
26211
|
annotations: {
|
|
26198
26212
|
title: "Code annotations",
|
|
@@ -26280,15 +26294,20 @@ code-viewer query clear --db app.db`
|
|
|
26280
26294
|
displaySource: "このブラウザのすべてのプロジェクトに適用されます。",
|
|
26281
26295
|
excludedDirectories: "除外ディレクトリ",
|
|
26282
26296
|
omitDirs: "閲覧と検索でスキップするディレクトリ名",
|
|
26297
|
+
omitDirsHelp: "これらのディレクトリの中身は読み込みません。サイドバー(Files)・Ctrl+K(ファイル検索)・Ctrl+G(grep)・Datastores・File change watcher の5機能すべてに適用されます。",
|
|
26283
26298
|
excludeNames: "完全に非表示にするファイル名またはディレクトリ名",
|
|
26299
|
+
excludeNamesHelp: "リスト中の名前に一致するファイル/ディレクトリを、サイドバー・検索結果・grep 結果から完全に消します。Skip と違い、名前自体が UI に出なくなります。",
|
|
26284
26300
|
reset: "デフォルトに戻す",
|
|
26285
26301
|
autosaveNote: "変更は自動で保存されます。",
|
|
26286
|
-
scopeSource: (project, source) => `このブラウザのプロジェクト "${project}" に保存されます。ソース: ${source}
|
|
26302
|
+
scopeSource: (project, source) => `このブラウザのプロジェクト "${project}" に保存されます。ソース: ${source}。サイドバー、Ctrl+K、Ctrl+G、Datastores、File change watcher で使われます。「デフォルトに戻す」でブラウザ側の上書きを削除します。`,
|
|
26287
26303
|
browserOverride: "ブラウザ側の上書き",
|
|
26288
26304
|
serverDefault: "サーバ既定値",
|
|
26289
26305
|
uploadsTitle: "アップロード",
|
|
26290
26306
|
uploadEnabledLabel: "ワークツリーへのファイルアップロードを許可する",
|
|
26291
|
-
uploadEnabledHelp: "オフにすると、このサーバを使う全員に対してワークツリーは読み取り専用になります。"
|
|
26307
|
+
uploadEnabledHelp: "オフにすると、このサーバを使う全員に対してワークツリーは読み取り専用になります。",
|
|
26308
|
+
watchTitle: "ファイル変更の監視",
|
|
26309
|
+
watchLimit: "監視するディレクトリ数の上限",
|
|
26310
|
+
watchLimitHelp: (defaultLimit) => `値を大きくすると深いツリーの変更を取りこぼしにくくなりますが、ファイルハンドル数を消費します。上の Skip リストと併用すると、重いフォルダ(node_modules, .git, dist など)を監視枠から外せます。既定値: ${defaultLimit}。`
|
|
26292
26311
|
},
|
|
26293
26312
|
annotations: {
|
|
26294
26313
|
title: "コード注釈",
|
|
@@ -26406,14 +26425,20 @@ code-viewer query clear --db app.db`
|
|
|
26406
26425
|
settingsSections[1].textContent = text2.settings.uploadsTitle;
|
|
26407
26426
|
if (settingsSections[2])
|
|
26408
26427
|
settingsSections[2].textContent = text2.settings.excludedDirectories;
|
|
26428
|
+
if (settingsSections[3])
|
|
26429
|
+
settingsSections[3].textContent = text2.settings.watchTitle;
|
|
26409
26430
|
setElementText("#upload-enabled-label", text2.settings.uploadEnabledLabel);
|
|
26410
26431
|
setElementText("#upload-help", text2.settings.uploadEnabledHelp);
|
|
26432
|
+
setElementText("#scope-omit-dirs-help", text2.settings.omitDirsHelp);
|
|
26433
|
+
setElementText("#scope-exclude-names-help", text2.settings.excludeNamesHelp);
|
|
26434
|
+
setElementText("#scope-watch-limit-help", text2.settings.watchLimitHelp(SERVER_SCOPE_WATCH_LIMIT_DEFAULT));
|
|
26411
26435
|
const labelMap = {
|
|
26412
26436
|
"viewer-language": text2.settings.language,
|
|
26413
26437
|
"sidebar-font-size": text2.settings.fileListFontSize,
|
|
26414
26438
|
"code-font-size": text2.settings.codeFontSize,
|
|
26415
26439
|
"scope-omit-dirs": text2.settings.omitDirs,
|
|
26416
|
-
"scope-exclude-names": text2.settings.excludeNames
|
|
26440
|
+
"scope-exclude-names": text2.settings.excludeNames,
|
|
26441
|
+
"scope-watch-limit": text2.settings.watchLimit
|
|
26417
26442
|
};
|
|
26418
26443
|
Object.entries(labelMap).forEach(([id, label]) => {
|
|
26419
26444
|
const labelEl = document.querySelector(`label[for="${id}"]`);
|
|
@@ -26597,6 +26622,19 @@ code-viewer query clear --db app.db`
|
|
|
26597
26622
|
`);
|
|
26598
26623
|
excludeInput.value = effectiveScopeExcludeNames().join(`
|
|
26599
26624
|
`);
|
|
26625
|
+
const watchLimitInput = document.querySelector("#scope-watch-limit");
|
|
26626
|
+
const watchLimitRange = document.querySelector("#scope-watch-limit-range");
|
|
26627
|
+
const watchLimitValue = effectiveScopeWatchLimit();
|
|
26628
|
+
if (watchLimitInput) {
|
|
26629
|
+
watchLimitInput.min = String(SERVER_SCOPE_WATCH_LIMIT_MIN);
|
|
26630
|
+
watchLimitInput.max = String(SERVER_SCOPE_WATCH_LIMIT_MAX);
|
|
26631
|
+
watchLimitInput.value = String(watchLimitValue);
|
|
26632
|
+
}
|
|
26633
|
+
if (watchLimitRange) {
|
|
26634
|
+
watchLimitRange.min = String(SERVER_SCOPE_WATCH_LIMIT_MIN);
|
|
26635
|
+
watchLimitRange.max = String(SERVER_SCOPE_WATCH_LIMIT_MAX);
|
|
26636
|
+
watchLimitRange.value = String(watchLimitValue);
|
|
26637
|
+
}
|
|
26600
26638
|
const uploadToggle = document.querySelector("#upload-enabled");
|
|
26601
26639
|
if (uploadToggle)
|
|
26602
26640
|
uploadToggle.checked = APP_SETTINGS.uploadEnabled !== false;
|
|
@@ -26653,6 +26691,41 @@ code-viewer query clear --db app.db`
|
|
|
26653
26691
|
refreshScopeSourceLabel();
|
|
26654
26692
|
refreshRepositoryTreeAfterSettings();
|
|
26655
26693
|
}
|
|
26694
|
+
function normalizeScopeWatchLimit(value) {
|
|
26695
|
+
const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : Number.NaN;
|
|
26696
|
+
if (!Number.isFinite(parsed))
|
|
26697
|
+
return null;
|
|
26698
|
+
const floored = Math.floor(parsed);
|
|
26699
|
+
if (floored < SERVER_SCOPE_WATCH_LIMIT_MIN)
|
|
26700
|
+
return SERVER_SCOPE_WATCH_LIMIT_MIN;
|
|
26701
|
+
if (floored > SERVER_SCOPE_WATCH_LIMIT_MAX)
|
|
26702
|
+
return SERVER_SCOPE_WATCH_LIMIT_MAX;
|
|
26703
|
+
return floored;
|
|
26704
|
+
}
|
|
26705
|
+
function effectiveScopeWatchLimit() {
|
|
26706
|
+
const saved = normalizeScopeWatchLimit(APP_SETTINGS.scopeWatchLimit);
|
|
26707
|
+
return saved ?? SERVER_SCOPE_WATCH_LIMIT_DEFAULT;
|
|
26708
|
+
}
|
|
26709
|
+
function syncScopeWatchLimitInputs(value) {
|
|
26710
|
+
const numberInput = document.querySelector("#scope-watch-limit");
|
|
26711
|
+
const rangeInput = document.querySelector("#scope-watch-limit-range");
|
|
26712
|
+
if (numberInput && numberInput.value !== String(value))
|
|
26713
|
+
numberInput.value = String(value);
|
|
26714
|
+
if (rangeInput && rangeInput.value !== String(value))
|
|
26715
|
+
rangeInput.value = String(value);
|
|
26716
|
+
}
|
|
26717
|
+
function saveScopeWatchLimitField(value) {
|
|
26718
|
+
const next = normalizeScopeWatchLimit(value);
|
|
26719
|
+
const resolved = next ?? SERVER_SCOPE_WATCH_LIMIT_DEFAULT;
|
|
26720
|
+
mergeLocalSettings({ scopeWatchLimit: resolved });
|
|
26721
|
+
patchSettings({ scopeWatchLimit: resolved });
|
|
26722
|
+
syncScopeWatchLimitInputs(resolved);
|
|
26723
|
+
}
|
|
26724
|
+
function previewScopeWatchLimit(value) {
|
|
26725
|
+
const next = normalizeScopeWatchLimit(value);
|
|
26726
|
+
if (next != null)
|
|
26727
|
+
syncScopeWatchLimitInputs(next);
|
|
26728
|
+
}
|
|
26656
26729
|
function resetScopeSettings() {
|
|
26657
26730
|
setViewerLanguage("en", false);
|
|
26658
26731
|
mergeLocalSettings({
|
|
@@ -26660,6 +26733,7 @@ code-viewer query clear --db app.db`
|
|
|
26660
26733
|
codeFontSize: null,
|
|
26661
26734
|
scopeOmitDirs: null,
|
|
26662
26735
|
scopeExcludeNames: null,
|
|
26736
|
+
scopeWatchLimit: null,
|
|
26663
26737
|
uploadEnabled: null
|
|
26664
26738
|
});
|
|
26665
26739
|
applySidebarFontSize("regular");
|
|
@@ -26670,6 +26744,7 @@ code-viewer query clear --db app.db`
|
|
|
26670
26744
|
codeFontSize: null,
|
|
26671
26745
|
scopeOmitDirs: null,
|
|
26672
26746
|
scopeExcludeNames: null,
|
|
26747
|
+
scopeWatchLimit: null,
|
|
26673
26748
|
uploadEnabled: null
|
|
26674
26749
|
});
|
|
26675
26750
|
const sidebarFontSize = document.querySelector("#sidebar-font-size");
|
|
@@ -27087,6 +27162,15 @@ code-viewer query clear --db app.db`
|
|
|
27087
27162
|
$("#scope-exclude-names")?.addEventListener("change", (event) => {
|
|
27088
27163
|
saveScopeExcludeNamesField(event.currentTarget.value);
|
|
27089
27164
|
});
|
|
27165
|
+
$("#scope-watch-limit")?.addEventListener("change", (event) => {
|
|
27166
|
+
saveScopeWatchLimitField(event.currentTarget.value);
|
|
27167
|
+
});
|
|
27168
|
+
$("#scope-watch-limit-range")?.addEventListener("input", (event) => {
|
|
27169
|
+
previewScopeWatchLimit(event.currentTarget.value);
|
|
27170
|
+
});
|
|
27171
|
+
$("#scope-watch-limit-range")?.addEventListener("change", (event) => {
|
|
27172
|
+
saveScopeWatchLimitField(event.currentTarget.value);
|
|
27173
|
+
});
|
|
27090
27174
|
$("#scope-settings-popover")?.addEventListener("keydown", (e2) => {
|
|
27091
27175
|
if (isImeComposing(e2))
|
|
27092
27176
|
return;
|
package/web/index.html
CHANGED
|
@@ -177,10 +177,21 @@
|
|
|
177
177
|
<strong class="scope-settings-section-title">Excluded directories</strong>
|
|
178
178
|
<label for="scope-omit-dirs">Skip these directory names while browsing and searching</label>
|
|
179
179
|
<textarea id="scope-omit-dirs" rows="6" spellcheck="false"></textarea>
|
|
180
|
+
<p id="scope-omit-dirs-help" class="scope-settings-help"></p>
|
|
180
181
|
<label for="scope-exclude-names">Hide these file or directory names completely</label>
|
|
181
182
|
<textarea id="scope-exclude-names" rows="4" spellcheck="false"></textarea>
|
|
183
|
+
<p id="scope-exclude-names-help" class="scope-settings-help"></p>
|
|
182
184
|
<p id="scope-omit-source"></p>
|
|
183
185
|
</div>
|
|
186
|
+
<div class="scope-settings-section">
|
|
187
|
+
<strong id="watch-section-title" class="scope-settings-section-title">File change watcher</strong>
|
|
188
|
+
<label for="scope-watch-limit">Maximum directories to watch</label>
|
|
189
|
+
<div class="scope-watch-limit-row">
|
|
190
|
+
<input id="scope-watch-limit-range" type="range" min="16" max="65536" step="16" aria-label="watch limit slider" />
|
|
191
|
+
<input id="scope-watch-limit" type="number" min="16" max="65536" step="1" />
|
|
192
|
+
</div>
|
|
193
|
+
<p id="scope-watch-limit-help" class="scope-settings-help"></p>
|
|
194
|
+
</div>
|
|
184
195
|
<div class="scope-settings-footer">
|
|
185
196
|
<p id="scope-settings-autosave-note" class="scope-settings-help"></p>
|
|
186
197
|
<button id="scope-omit-reset" type="button">Restore defaults</button>
|
package/web/style.css
CHANGED
|
@@ -1735,6 +1735,20 @@ body.gdp-history-resizing * {
|
|
|
1735
1735
|
gap: 8px;
|
|
1736
1736
|
margin-top: 10px;
|
|
1737
1737
|
}
|
|
1738
|
+
.scope-watch-limit-row {
|
|
1739
|
+
display: flex;
|
|
1740
|
+
align-items: center;
|
|
1741
|
+
gap: 10px;
|
|
1742
|
+
}
|
|
1743
|
+
.scope-watch-limit-row input[type="range"] {
|
|
1744
|
+
flex: 1;
|
|
1745
|
+
min-width: 0;
|
|
1746
|
+
accent-color: var(--accent, #2b6cb0);
|
|
1747
|
+
}
|
|
1748
|
+
.scope-watch-limit-row input[type="number"] {
|
|
1749
|
+
width: 88px;
|
|
1750
|
+
flex: 0 0 auto;
|
|
1751
|
+
}
|
|
1738
1752
|
.scope-settings-toggle {
|
|
1739
1753
|
display: flex;
|
|
1740
1754
|
align-items: center;
|