167 lines
4.6 KiB
TypeScript
167 lines
4.6 KiB
TypeScript
// Config resolution for user-defined status line commands.
|
|
// Precedence: local project > project > global settings.
|
|
|
|
import type { StatusLineConfig } from "../../settings-manager";
|
|
import { settingsManager } from "../../settings-manager";
|
|
import { debugLog } from "../../utils/debug";
|
|
|
|
/** Minimum allowed polling interval (1 second). */
|
|
export const MIN_STATUS_LINE_INTERVAL_MS = 1_000;
|
|
|
|
/** Default execution timeout (5 seconds). */
|
|
export const DEFAULT_STATUS_LINE_TIMEOUT_MS = 5_000;
|
|
|
|
/** Maximum allowed execution timeout (30 seconds). */
|
|
export const MAX_STATUS_LINE_TIMEOUT_MS = 30_000;
|
|
|
|
/** Default trigger debounce (300ms). */
|
|
export const DEFAULT_STATUS_LINE_DEBOUNCE_MS = 300;
|
|
|
|
/** Minimum allowed debounce. */
|
|
export const MIN_STATUS_LINE_DEBOUNCE_MS = 50;
|
|
|
|
/** Maximum allowed debounce. */
|
|
export const MAX_STATUS_LINE_DEBOUNCE_MS = 5_000;
|
|
|
|
/** Maximum allowed padding. */
|
|
export const MAX_STATUS_LINE_PADDING = 16;
|
|
|
|
export interface NormalizedStatusLineConfig {
|
|
type: "command";
|
|
command: string;
|
|
padding: number;
|
|
timeout: number;
|
|
debounceMs: number;
|
|
refreshIntervalMs?: number;
|
|
disabled?: boolean;
|
|
}
|
|
|
|
/**
|
|
* Clamp status line config to valid ranges and fill defaults.
|
|
*/
|
|
export function normalizeStatusLineConfig(
|
|
config: StatusLineConfig,
|
|
): NormalizedStatusLineConfig {
|
|
const refreshIntervalMs =
|
|
config.refreshIntervalMs === undefined
|
|
? undefined
|
|
: Math.max(MIN_STATUS_LINE_INTERVAL_MS, config.refreshIntervalMs);
|
|
|
|
return {
|
|
type: "command",
|
|
command: config.command,
|
|
padding: Math.max(
|
|
0,
|
|
Math.min(MAX_STATUS_LINE_PADDING, config.padding ?? 0),
|
|
),
|
|
timeout: Math.min(
|
|
MAX_STATUS_LINE_TIMEOUT_MS,
|
|
Math.max(1_000, config.timeout ?? DEFAULT_STATUS_LINE_TIMEOUT_MS),
|
|
),
|
|
debounceMs: Math.max(
|
|
MIN_STATUS_LINE_DEBOUNCE_MS,
|
|
Math.min(
|
|
MAX_STATUS_LINE_DEBOUNCE_MS,
|
|
config.debounceMs ?? DEFAULT_STATUS_LINE_DEBOUNCE_MS,
|
|
),
|
|
),
|
|
...(refreshIntervalMs !== undefined && { refreshIntervalMs }),
|
|
...(config.disabled !== undefined && { disabled: config.disabled }),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Check whether the status line is disabled across settings levels.
|
|
*
|
|
* Precedence (mirrors `areHooksDisabled` in hooks/loader.ts):
|
|
* 1. User `disabled: false` → ENABLED (explicit override)
|
|
* 2. User `disabled: true` → DISABLED
|
|
* 3. Project or local-project `disabled: true` → DISABLED
|
|
* 4. Default → ENABLED (if a config exists)
|
|
*/
|
|
export function isStatusLineDisabled(
|
|
workingDirectory: string = process.cwd(),
|
|
): boolean {
|
|
try {
|
|
const userDisabled = settingsManager.getSettings().statusLine?.disabled;
|
|
if (userDisabled === false) return false;
|
|
if (userDisabled === true) return true;
|
|
|
|
try {
|
|
const projectDisabled =
|
|
settingsManager.getProjectSettings(workingDirectory)?.statusLine
|
|
?.disabled;
|
|
if (projectDisabled === true) return true;
|
|
} catch {
|
|
// Project settings not loaded
|
|
}
|
|
|
|
try {
|
|
const localDisabled =
|
|
settingsManager.getLocalProjectSettings(workingDirectory)?.statusLine
|
|
?.disabled;
|
|
if (localDisabled === true) return true;
|
|
} catch {
|
|
// Local project settings not loaded
|
|
}
|
|
|
|
return false;
|
|
} catch (error) {
|
|
debugLog(
|
|
"statusline",
|
|
"isStatusLineDisabled: Failed to check disabled status",
|
|
error,
|
|
);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Resolve effective status line config from all settings levels.
|
|
* Returns null if no config is defined or the status line is disabled.
|
|
*
|
|
* Precedence: local project > project > global.
|
|
*/
|
|
export function resolveStatusLineConfig(
|
|
workingDirectory: string = process.cwd(),
|
|
): NormalizedStatusLineConfig | null {
|
|
try {
|
|
if (isStatusLineDisabled(workingDirectory)) return null;
|
|
|
|
// Local project settings (highest priority)
|
|
try {
|
|
const local =
|
|
settingsManager.getLocalProjectSettings(workingDirectory)?.statusLine;
|
|
if (local?.command) return normalizeStatusLineConfig(local);
|
|
} catch {
|
|
// Not loaded
|
|
}
|
|
|
|
// Project settings
|
|
try {
|
|
const project =
|
|
settingsManager.getProjectSettings(workingDirectory)?.statusLine;
|
|
if (project?.command) return normalizeStatusLineConfig(project);
|
|
} catch {
|
|
// Not loaded
|
|
}
|
|
|
|
// Global settings
|
|
try {
|
|
const global = settingsManager.getSettings().statusLine;
|
|
if (global?.command) return normalizeStatusLineConfig(global);
|
|
} catch {
|
|
// Not initialized
|
|
}
|
|
|
|
return null;
|
|
} catch (error) {
|
|
debugLog(
|
|
"statusline",
|
|
"resolveStatusLineConfig: Failed to resolve config",
|
|
error,
|
|
);
|
|
return null;
|
|
}
|
|
}
|