summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md16
-rw-r--r--package-lock.json12
-rw-r--r--package.json3
-rw-r--r--src/osc-notify-decorator.ts24
-rw-r--r--src/osc-notify-middleware.ts36
5 files changed, 73 insertions, 18 deletions
diff --git a/README.md b/README.md
index c735aa8..7ba1514 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,22 @@ format:
OSC 9 ; [message] ST
```
+Clicking the notification brings Tabby to the front and switches to the exact
+tab/pane that emitted the sequence. The notification title reflects the tab's
+current title at the time the sequence is received.
+
+The OSC 9 title is cleaned up: it prefers a user-set custom tab name, and when
+the title looks like a filesystem path (e.g. a shell tab showing its cwd) only
+the last path segment is used instead of the full, often-truncated path.
+
+`OSC 777 ; notify ; title ; body` (the rxvt/urxvt notification form) is also
+supported, letting a program set an explicit title and body:
+
+```sh
+# creates a notification titled 'Build' with body 'Done'
+printf "\033]777;notify;Build;Done\a"
+```
+
### Example commands
```sh
diff --git a/package-lock.json b/package-lock.json
index b847053..b3f1930 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,16 +1,17 @@
{
"name": "tabby-osc-notify",
- "version": "1.0.0",
+ "version": "1.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "tabby-osc-notify",
- "version": "1.0.0",
+ "version": "1.1.0",
"license": "MIT",
"dependencies": {
"@angular/core": "^15",
"rxjs": "^7.8.1",
+ "tabby-core": "^1.0.197-nightly.1",
"tabby-terminal": "^1.0.197-nightly.1"
},
"devDependencies": {
@@ -3283,11 +3284,10 @@
}
},
"node_modules/tabby-core": {
- "version": "1.0.231-nightly.0",
- "resolved": "https://registry.npmjs.org/tabby-core/-/tabby-core-1.0.231-nightly.0.tgz",
- "integrity": "sha512-CpOLTw9XWLeSJoAXGf6CIH1m5DULvmNTIncy0n0n8PAewQZmhMf5JYMzwiBzey+54LDZ/yit9aBRgat7yGx+Eg==",
+ "version": "1.0.197-nightly.1",
+ "resolved": "https://registry.npmjs.org/tabby-core/-/tabby-core-1.0.197-nightly.1.tgz",
+ "integrity": "sha512-GS4Q3orewMdZk4HAJp1vVg/Pv+FcN7E3o6TJHaUtPHRTWSeNM4MOoHY2HJINgcjaFuInthe4+8dK1W2aIECy2Q==",
"license": "MIT",
- "peer": true,
"peerDependencies": {
"@angular/animations": "^15",
"@angular/common": "^15",
diff --git a/package.json b/package.json
index b12143b..81c3c25 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "tabby-osc-notify",
- "version": "1.0.0",
+ "version": "1.1.0",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"scripts": {
@@ -32,6 +32,7 @@
"dependencies": {
"@angular/core": "^15",
"rxjs": "^7.8.1",
+ "tabby-core": "^1.0.197-nightly.1",
"tabby-terminal": "^1.0.197-nightly.1"
},
"allowScripts": {
diff --git a/src/osc-notify-decorator.ts b/src/osc-notify-decorator.ts
index 7d32f1c..4beb029 100644
--- a/src/osc-notify-decorator.ts
+++ b/src/osc-notify-decorator.ts
@@ -1,25 +1,41 @@
import OscNotifyMiddleware from "./osc-notify-middleware";
import { Injectable } from "@angular/core";
import { TerminalDecorator, BaseSession, BaseTerminalTabComponent } from "tabby-terminal";
+import { AppService, HostWindowService } from "tabby-core";
@Injectable()
export default class OscNotifyDecorator extends TerminalDecorator {
+ constructor(
+ private app: AppService,
+ private hostWindow: HostWindowService,
+ ) {
+ super();
+ }
+
attach(tab: BaseTerminalTabComponent<any>): void {
// Subscribe to attach to future sessions in this tab
tab.sessionChanged$.subscribe((session) => {
if (session) {
- this.attachToSession(session, (<any>tab).title);
+ this.attachToSession(session, tab);
}
});
// Attach the current session for this tab
if (tab.session) {
- this.attachToSession(tab.session, (<any>tab).title);
+ this.attachToSession(tab.session, tab);
}
}
- private attachToSession(session: BaseSession, tabTitle: string) {
- const middleware = new OscNotifyMiddleware(tabTitle);
+ private attachToSession(session: BaseSession, tab: BaseTerminalTabComponent<any>) {
+ const middleware = new OscNotifyMiddleware(
+ () => (<any>tab).customTitle || (<any>tab).title,
+ () => {
+ this.hostWindow.bringToFront();
+ const parent = this.app.getParentTab(tab);
+ this.app.selectTab(parent ?? tab);
+ parent?.focus(tab);
+ },
+ );
session.middleware.push(middleware);
}
diff --git a/src/osc-notify-middleware.ts b/src/osc-notify-middleware.ts
index 15548f4..dcfcc1a 100644
--- a/src/osc-notify-middleware.ts
+++ b/src/osc-notify-middleware.ts
@@ -4,13 +4,25 @@ import { Observable, Subject } from "rxjs";
const oscPrefix = Buffer.from("\x1b]");
const oscSuffix = Buffer.from("\x07");
+function cleanTitle(raw: string): string {
+ const t = (raw ?? "").trim();
+ if (!t) return "Terminal";
+ if (t.includes("/") || t.includes("\\")) {
+ const segs = t.split(/[/\\]/).filter(s => s.length > 0);
+ return segs.length ? segs[segs.length - 1] : t;
+ }
+ return t;
+}
+
export default class OscNotifyMiddleware extends SessionMiddleware {
- tabTitle: string;
+ getTitle: () => string;
+ onClick: () => void;
- constructor(tabTitle: string) {
+ constructor(getTitle: () => string, onClick: () => void) {
super();
- this.tabTitle = tabTitle;
+ this.getTitle = getTitle;
+ this.onClick = onClick;
}
get cwdReported$(): Observable<string> {
@@ -22,6 +34,7 @@ export default class OscNotifyMiddleware extends SessionMiddleware {
private cwdReported = new Subject<string>();
private copyRequested = new Subject<string>();
+ private notifications: Notification[] = [];
feedFromSession(data: Buffer): void {
let startIndex = 0;
@@ -36,10 +49,11 @@ export default class OscNotifyMiddleware extends SessionMiddleware {
const oscCode = parseInt(oscCodeString);
if (oscCode === 9) {
- // TODO: onclick switch to tab
- new Notification(this.tabTitle, {
- body: oscParams[0]
- });
+ this.showNotification(cleanTitle(this.getTitle()), oscParams[0] ?? "");
+ } else if (oscCode === 777 && oscParams[0] === "notify") {
+ const title = oscParams[1] || cleanTitle(this.getTitle());
+ const body = oscParams.slice(2).join(";");
+ this.showNotification(title, body);
} else {
continue;
}
@@ -48,7 +62,15 @@ export default class OscNotifyMiddleware extends SessionMiddleware {
super.feedFromSession(data);
}
+ private showNotification(title: string, body: string): void {
+ const notification = new Notification(title || "Terminal", { body });
+ notification.onclick = () => this.onClick();
+ this.notifications.push(notification);
+ }
+
close(): void {
+ this.notifications.forEach((notification) => notification.close());
+ this.notifications = [];
this.cwdReported.complete();
this.copyRequested.complete();
super.close();