mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-15 02:49:33 +01:00
Merge pull request #740: feat(terminal): resolve relative path links against the pane's current directory
This commit is contained in:
commit
4f50af6a9f
14 files changed
+896
-8
No files matched your search
@@ -2426,6 +2426,31 @@ function resolveLinkedFilePath(filePath, workingDir) {
|
||||
return `/${parts.join('/')}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* The directory a RELATIVE path printed for a session is relative TO.
|
||||
*
|
||||
* `workingDir` is recorded once at create time and never follows a `cd`, so it
|
||||
* stops describing where a shell (or an agent that changed directory) really
|
||||
* is. `session.cwd` is the pane's live `#{pane_current_path}`, published by the
|
||||
* server from its pane read. It only changes which BASE a relative path joins;
|
||||
* the result is then routed like any other path, so a target outside the
|
||||
* workspace still goes through the attachment routes.
|
||||
*
|
||||
* Remote and Docker sessions are excluded (the server never sends them a cwd,
|
||||
* and this checks again): their local pane runs the ssh / docker-exec CLIENT,
|
||||
* so its directory says nothing about the agent. An unknown cwd falls back to
|
||||
* `workingDir`.
|
||||
*
|
||||
* @param {{workingDir?: string, cwd?: string, remote?: unknown, docker?: unknown}} [session]
|
||||
* @returns {string|undefined}
|
||||
*/
|
||||
function relativeResolutionBase(session) {
|
||||
if (!session) return undefined;
|
||||
const cwd = session.cwd;
|
||||
if (!session.remote && !session.docker && typeof cwd === 'string' && cwd.startsWith('/')) return cwd;
|
||||
return session.workingDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extensions the file preview renders as a PAGE, from the sandboxed
|
||||
* `/html-view/<cap>/` route (src/web/routes/html-view-routes.ts, whose
|
||||
@@ -4088,6 +4113,7 @@ if (typeof window !== 'undefined') {
|
||||
absoluteFilePathPattern,
|
||||
findFilePathLinks,
|
||||
resolveLinkedFilePath,
|
||||
relativeResolutionBase,
|
||||
previewsInFileViewer,
|
||||
FILE_PREVIEW_EXTENSIONS,
|
||||
rendersAsPage,
|
||||
|
||||
@@ -2146,13 +2146,16 @@ Object.assign(CodemanApp.prototype, {
|
||||
|
||||
/**
|
||||
* A clicked path as the preview needs it: relative paths resolved against the
|
||||
* session's working directory, absolute and `~/` paths unchanged
|
||||
* directory the session's pane is in now, else its working directory
|
||||
* (`relativeResolutionBase`), absolute and `~/` paths unchanged
|
||||
* (`resolveLinkedFilePath`, constants.js). Shared by the terminal link
|
||||
* provider and the response viewer, so one path opens the same file in both.
|
||||
*/
|
||||
_resolveLinkedFilePath(filePath, sessionId) {
|
||||
if (typeof resolveLinkedFilePath !== 'function') return filePath;
|
||||
return resolveLinkedFilePath(filePath, this.sessions?.get?.(sessionId)?.workingDir);
|
||||
const session = this.sessions?.get?.(sessionId);
|
||||
const base = typeof relativeResolutionBase === 'function' ? relativeResolutionBase(session) : session?.workingDir;
|
||||
return resolveLinkedFilePath(filePath, base);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
+13
-2
@@ -2854,13 +2854,24 @@ export class WebServer extends EventEmitter {
|
||||
private applyPaneExits(): void {
|
||||
const getPaneExit = this.mux.getPaneExit?.bind(this.mux);
|
||||
if (!getPaneExit) return;
|
||||
const getPaneCurrentPath = this.mux.getPaneCurrentPath?.bind(this.mux);
|
||||
for (const session of this.sessions.values()) {
|
||||
const muxName = session.muxName;
|
||||
// No pane, so nothing to report — and `setPaneExit()` would force UNKNOWN
|
||||
// for such a session anyway.
|
||||
if (!muxName) continue;
|
||||
if (!session.setPaneExit(getPaneExit(muxName))) continue;
|
||||
this.persistSessionState(session);
|
||||
// The pane's live directory rides the same read: it is the base a relative
|
||||
// path printed in the terminal resolves against. The manager's answer is
|
||||
// applied as given, `undefined` included: it keeps its map across a failed
|
||||
// or empty read and carries a blank `#{pane_current_path}` forward, so an
|
||||
// `undefined` here means an authoritative read listed no single directory
|
||||
// for the session (split into several panes, or gone from the socket).
|
||||
const cwdChanged = getPaneCurrentPath ? session.setCwd(getPaneCurrentPath(muxName)) : false;
|
||||
if (session.setPaneExit(getPaneExit(muxName))) {
|
||||
this.persistSessionState(session);
|
||||
} else if (!cwdChanged) {
|
||||
continue;
|
||||
}
|
||||
this.broadcastSessionStateDebounced(session.id);
|
||||
}
|
||||
this.closeCleanlyExitedSessions();
|
||||
|
||||
Reference in new issue
Block a user