@akiojin/gwt 9.7.0 → 9.8.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/README.ja.md CHANGED
@@ -6,10 +6,14 @@ gwt は Git worktree の管理と、`Claude Code` / `Codex` / `Gemini` /
6
6
  ## インストール
7
7
 
8
8
  [GitHub Releases](https://github.com/akiojin/gwt/releases) からお使いの
9
- プラットフォーム向けバイナリをダウンロードし、`PATH` に配置してください。
9
+ プラットフォーム向け release asset を取得してください。
10
10
 
11
11
  ### macOS
12
12
 
13
+ - GUI 向けの主配布物: `gwt-macos-universal.dmg`
14
+ - マウントした DMG から `GWT.app` を開くとネイティブ GUI をそのまま起動できます
15
+ - `PATH` に `gwt` を入れたい場合は install script を使います
16
+
13
17
  ```bash
14
18
  curl -fsSL https://raw.githubusercontent.com/akiojin/gwt/main/installers/macos/install.sh | bash
15
19
  ```
@@ -17,12 +21,21 @@ curl -fsSL https://raw.githubusercontent.com/akiojin/gwt/main/installers/macos/i
17
21
  特定バージョンを指定する場合:
18
22
 
19
23
  ```bash
20
- curl -fsSL https://raw.githubusercontent.com/akiojin/gwt/main/installers/macos/install.sh | bash -s -- --version 6.30.3
24
+ curl -fsSL https://raw.githubusercontent.com/akiojin/gwt/main/installers/macos/install.sh | bash -s -- --version <version>
21
25
  ```
22
26
 
23
- ### Windows / Linux
27
+ ### Windows
28
+
29
+ - GUI 向けの主配布物: `gwt-windows-x86_64.msi`
30
+ - portable bundle: `gwt-windows-x86_64.zip`
31
+ - public front door は `gwt.exe` で、`gwtd.exe` は内部 runtime 用の companion binary です
24
32
 
25
- GitHub Releases からバイナリを取得して `PATH` に配置します。
33
+ ### Linux
34
+
35
+ - portable bundle:
36
+ - `gwt-linux-x86_64.tar.gz`
37
+ - `gwt-linux-aarch64.tar.gz`
38
+ - 展開した `gwt` / `gwtd` を `PATH` 上のディレクトリへ配置します
26
39
 
27
40
  ### アンインストール(macOS)
28
41
 
@@ -140,13 +153,13 @@ gwt issue spec <number> --section spec|plan|tasks
140
153
  ### ビルド
141
154
 
142
155
  ```bash
143
- cargo build -p gwt
156
+ cargo build -p gwt --bin gwt --bin gwtd
144
157
  ```
145
158
 
146
159
  ### 実行
147
160
 
148
161
  ```bash
149
- cargo run -p gwt
162
+ cargo run -p gwt --bin gwt
150
163
  ```
151
164
 
152
165
  ### macOS 向け `.app` bundle
@@ -162,6 +175,24 @@ cargo bundle -p gwt --format osx
162
175
  cargo test -p gwt-core -p gwt --all-features
163
176
  ```
164
177
 
178
+ ### Release Asset Contract
179
+
180
+ ```bash
181
+ npm run test:release-assets
182
+ ```
183
+
184
+ ### Frontend Bundle Contract
185
+
186
+ ```bash
187
+ npm run test:frontend-bundle
188
+ ```
189
+
190
+ ### Release Flow Checks
191
+
192
+ ```bash
193
+ npm run test:release-flow
194
+ ```
195
+
165
196
  ### Lint
166
197
 
167
198
  ```bash
package/README.md CHANGED
@@ -7,12 +7,15 @@ such as `Claude Code`, `Codex`, `Gemini`, and `OpenCode`.
7
7
 
8
8
  ## Install
9
9
 
10
- Download the binary for your platform from
11
- [GitHub Releases](https://github.com/akiojin/gwt/releases) and place it in
12
- your `PATH`.
10
+ Download the release asset for your platform from
11
+ [GitHub Releases](https://github.com/akiojin/gwt/releases).
13
12
 
14
13
  ### macOS
15
14
 
15
+ - GUI-first installer: `gwt-macos-universal.dmg`
16
+ - Open `GWT.app` from the mounted DMG for the native desktop launch surface
17
+ - Use the install script when you want the `gwt` CLI front door in your `PATH`
18
+
16
19
  ```bash
17
20
  curl -fsSL https://raw.githubusercontent.com/akiojin/gwt/main/installers/macos/install.sh | bash
18
21
  ```
@@ -20,12 +23,21 @@ curl -fsSL https://raw.githubusercontent.com/akiojin/gwt/main/installers/macos/i
20
23
  Install a specific version:
21
24
 
22
25
  ```bash
23
- curl -fsSL https://raw.githubusercontent.com/akiojin/gwt/main/installers/macos/install.sh | bash -s -- --version 6.30.3
26
+ curl -fsSL https://raw.githubusercontent.com/akiojin/gwt/main/installers/macos/install.sh | bash -s -- --version <version>
24
27
  ```
25
28
 
26
- ### Windows / Linux
29
+ ### Windows
30
+
31
+ - GUI-first installer: `gwt-windows-x86_64.msi`
32
+ - Portable bundle: `gwt-windows-x86_64.zip`
33
+ - The public front door is `gwt.exe`; `gwtd.exe` is bundled for internal runtime use
27
34
 
28
- Download the binary from GitHub Releases and add it to your `PATH`.
35
+ ### Linux
36
+
37
+ - Portable bundles:
38
+ - `gwt-linux-x86_64.tar.gz`
39
+ - `gwt-linux-aarch64.tar.gz`
40
+ - Extract `gwt` and `gwtd` into a directory on your `PATH`
29
41
 
30
42
  ### Uninstall (macOS)
31
43
 
@@ -144,13 +156,13 @@ gwt issue spec <number> --section spec|plan|tasks
144
156
  ### Build
145
157
 
146
158
  ```bash
147
- cargo build -p gwt
159
+ cargo build -p gwt --bin gwt --bin gwtd
148
160
  ```
149
161
 
150
162
  ### Run
151
163
 
152
164
  ```bash
153
- cargo run -p gwt
165
+ cargo run -p gwt --bin gwt
154
166
  ```
155
167
 
156
168
  ### Build a macOS app bundle
@@ -166,6 +178,24 @@ cargo bundle -p gwt --format osx
166
178
  cargo test -p gwt-core -p gwt --all-features
167
179
  ```
168
180
 
181
+ ### Release Asset Contract
182
+
183
+ ```bash
184
+ npm run test:release-assets
185
+ ```
186
+
187
+ ### Frontend Bundle Contract
188
+
189
+ ```bash
190
+ npm run test:frontend-bundle
191
+ ```
192
+
193
+ ### Release Flow Checks
194
+
195
+ ```bash
196
+ npm run test:release-flow
197
+ ```
198
+
169
199
  ### Lint
170
200
 
171
201
  ```bash
Binary file
Binary file
Binary file
@@ -0,0 +1,18 @@
1
+ {
2
+ "bundle_binaries": {
3
+ "linux": ["gwt", "gwtd"],
4
+ "macos": ["gwt", "gwtd"],
5
+ "windows": ["gwt.exe", "gwtd.exe"]
6
+ },
7
+ "portable_assets": {
8
+ "linux-x86_64": "gwt-linux-x86_64.tar.gz",
9
+ "linux-aarch64": "gwt-linux-aarch64.tar.gz",
10
+ "macos-x86_64": "gwt-macos-x86_64.tar.gz",
11
+ "macos-aarch64": "gwt-macos-arm64.tar.gz",
12
+ "windows-x86_64": "gwt-windows-x86_64.zip"
13
+ },
14
+ "installer_assets": {
15
+ "macos": "gwt-macos-universal.dmg",
16
+ "windows": "gwt-windows-x86_64.msi"
17
+ }
18
+ }
@@ -8,8 +8,8 @@ services:
8
8
  - bash-history:/root/.bash_history_dir
9
9
  - claude-config:/root/.claude
10
10
  - codex-config:/root/.codex
11
- - ${HOME:?HOME must be set}/.claude:/root/.claude-host:ro
12
- - ${HOME:?HOME must be set}/.codex:/root/.codex-host:ro
11
+ - ${HOME:-${USERPROFILE:?HOME or USERPROFILE must be set}}/.claude:/root/.claude-host:ro
12
+ - ${HOME:-${USERPROFILE:?HOME or USERPROFILE must be set}}/.codex:/root/.codex-host:ro
13
13
  ports:
14
14
  - ${PORT:-3000}:3000
15
15
  extra_hosts:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akiojin/gwt",
3
- "version": "9.7.0",
3
+ "version": "9.8.0",
4
4
  "description": "Desktop GUI for Git worktree management and coding agent launch",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,9 +8,12 @@
8
8
  },
9
9
  "scripts": {
10
10
  "postinstall": "node scripts/postinstall.cjs",
11
- "dev": "cargo run -p gwt",
12
- "build": "cargo build --release -p gwt",
11
+ "dev": "cargo run -p gwt --bin gwt",
12
+ "build": "cargo build --release -p gwt --bin gwt --bin gwtd",
13
13
  "test": "cargo test -p gwt-core -p gwt --all-features",
14
+ "test:frontend-bundle": "node --check crates/gwt/web/app.js",
15
+ "test:release-assets": "node scripts/test_release_assets.cjs",
16
+ "test:release-flow": "bash scripts/check-release-flow.sh",
14
17
  "test:all": "bash scripts/test-all.sh",
15
18
  "prepare": "test -n \"$CI\" || bunx husky install",
16
19
  "lint:skills": "bash scripts/validate-skill-frontmatter.sh",
@@ -5,6 +5,8 @@ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5
5
  RELEASE="$ROOT/.github/workflows/release.yml"
6
6
  README_EN="$ROOT/README.md"
7
7
  README_JA="$ROOT/README.ja.md"
8
+ INDEX_HTML="$ROOT/crates/gwt/web/index.html"
9
+ APP_JS="$ROOT/crates/gwt/web/app.js"
8
10
 
9
11
  fail=0
10
12
 
@@ -23,6 +25,21 @@ if grep -q "release-guide" "$README_EN" "$README_JA"; then
23
25
  fail=1
24
26
  fi
25
27
 
28
+ if ! grep -q '<script type="module" src="/app.js"></script>' "$INDEX_HTML"; then
29
+ echo "[FAIL] index.html no longer points at the shared /app.js frontend bundle"
30
+ fail=1
31
+ fi
32
+
33
+ if ! node "$ROOT/scripts/test_release_assets.cjs"; then
34
+ echo "[FAIL] release asset contract check failed"
35
+ fail=1
36
+ fi
37
+
38
+ if ! node --check "$APP_JS"; then
39
+ echo "[FAIL] frontend bundle syntax check failed"
40
+ fail=1
41
+ fi
42
+
26
43
  if [ "$fail" -ne 0 ]; then
27
44
  exit 1
28
45
  fi
@@ -36,6 +36,16 @@ function releaseAssetName(platform = os.platform(), arch = os.arch()) {
36
36
  throw new Error(`Unsupported platform: ${platform}-${arch}`);
37
37
  }
38
38
 
39
+ function primaryReleaseAssetName(platform = os.platform(), arch = os.arch()) {
40
+ if (platform === "darwin" && (arch === "arm64" || arch === "x64")) {
41
+ return "gwt-macos-universal.dmg";
42
+ }
43
+ if (platform === "win32" && arch === "x64") {
44
+ return "gwt-windows-x86_64.msi";
45
+ }
46
+ return releaseAssetName(platform, arch);
47
+ }
48
+
39
49
  function releaseAssetUrl(repo, version, platform = os.platform(), arch = os.arch()) {
40
50
  const asset = releaseAssetName(platform, arch);
41
51
  const tag = `v${version}`;
@@ -197,6 +207,7 @@ module.exports = {
197
207
  installBinaryFromArchive: installBundleFromArchive,
198
208
  installBundleFromArchive,
199
209
  installReleaseBinary,
210
+ primaryReleaseAssetName,
200
211
  releaseAssetName,
201
212
  releaseAssetUrl,
202
213
  };
@@ -1,9 +1,23 @@
1
1
  #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
- cargo test -p gwt-core -p gwt --all-features &
4
+ cargo_cmd="cargo"
5
+ if ! command -v "$cargo_cmd" >/dev/null 2>&1; then
6
+ if command -v cargo.exe >/dev/null 2>&1; then
7
+ cargo_cmd="cargo.exe"
8
+ else
9
+ echo "[FAIL] cargo or cargo.exe is required on PATH" >&2
10
+ exit 1
11
+ fi
12
+ fi
13
+
14
+ "$cargo_cmd" test -p gwt-core -p gwt --all-features &
5
15
  pid_rust=$!
6
16
 
17
+ bash scripts/check-release-flow.sh &
18
+ pid_release_flow=$!
19
+
7
20
  fail=0
8
21
  wait $pid_rust || fail=1
22
+ wait $pid_release_flow || fail=1
9
23
  exit $fail
@@ -8,6 +8,7 @@ const {
8
8
  binaryNameForPlatform,
9
9
  bundleBinaryNamesForPlatform,
10
10
  installBundleFromArchive,
11
+ primaryReleaseAssetName,
11
12
  releaseAssetName,
12
13
  } = require("./release-assets.cjs");
13
14
  const postinstall = require("./postinstall.cjs");
@@ -34,6 +35,14 @@ run("release asset names match the public portable contract", () => {
34
35
  assert.equal(releaseAssetName("win32", "x64"), "gwt-windows-x86_64.zip");
35
36
  });
36
37
 
38
+ run("primary release asset names match the GUI-first install contract", () => {
39
+ assert.equal(primaryReleaseAssetName("darwin", "arm64"), "gwt-macos-universal.dmg");
40
+ assert.equal(primaryReleaseAssetName("darwin", "x64"), "gwt-macos-universal.dmg");
41
+ assert.equal(primaryReleaseAssetName("linux", "arm64"), "gwt-linux-aarch64.tar.gz");
42
+ assert.equal(primaryReleaseAssetName("linux", "x64"), "gwt-linux-x86_64.tar.gz");
43
+ assert.equal(primaryReleaseAssetName("win32", "x64"), "gwt-windows-x86_64.msi");
44
+ });
45
+
37
46
  run("release helper keeps platform binary names stable", () => {
38
47
  assert.equal(binaryNameForPlatform("win32"), "gwt.exe");
39
48
  assert.equal(binaryNameForPlatform("linux"), "gwt");
@@ -67,6 +76,60 @@ run("release workflow packages gwtd alongside gwt", () => {
67
76
  assert.match(workflow, /Contents\/MacOS\/gwtd/);
68
77
  });
69
78
 
79
+ run("package scripts keep the GUI front door and release contract explicit", () => {
80
+ const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf8"));
81
+ assert.equal(pkg.scripts["test:release-assets"], "node scripts/test_release_assets.cjs");
82
+ assert.equal(
83
+ pkg.scripts["test:frontend-bundle"],
84
+ "node --check crates/gwt/web/app.js"
85
+ );
86
+ assert.equal(pkg.scripts["test:release-flow"], "bash scripts/check-release-flow.sh");
87
+ assert.equal(pkg.scripts.dev, "cargo run -p gwt --bin gwt");
88
+ assert.equal(pkg.scripts.build, "cargo build --release -p gwt --bin gwt --bin gwtd");
89
+ });
90
+
91
+ run("test all script keeps rust tests plus frontend release checks", () => {
92
+ const testAll = fs.readFileSync(path.join(__dirname, "test-all.sh"), "utf8");
93
+ assert.match(testAll, /test -p gwt-core -p gwt --all-features/);
94
+ assert.match(testAll, /cargo\.exe/);
95
+ assert.match(testAll, /bash scripts\/check-release-flow\.sh/);
96
+ });
97
+
98
+ run("release flow helper checks the shared frontend bundle and release assets", () => {
99
+ const releaseFlow = fs.readFileSync(path.join(__dirname, "check-release-flow.sh"), "utf8");
100
+ assert.match(releaseFlow, /scripts\/test_release_assets\.cjs/);
101
+ assert.match(releaseFlow, /node --check \"\$APP_JS\"/);
102
+ assert.match(releaseFlow, /script type=\"module\" src=\"\/app\.js\"/);
103
+ });
104
+
105
+ run("CI workflows call the named frontend and release verification scripts", () => {
106
+ const lintWorkflow = fs.readFileSync(
107
+ path.join(__dirname, "..", ".github", "workflows", "lint.yml"),
108
+ "utf8"
109
+ );
110
+ const testWorkflow = fs.readFileSync(
111
+ path.join(__dirname, "..", ".github", "workflows", "test.yml"),
112
+ "utf8"
113
+ );
114
+
115
+ assert.match(lintWorkflow, /test:frontend-bundle/);
116
+ assert.match(lintWorkflow, /test:release-flow/);
117
+ assert.match(testWorkflow, /test:release-assets/);
118
+ });
119
+
120
+ run("README install guidance points to GUI-first release assets", () => {
121
+ const readme = fs.readFileSync(path.join(__dirname, "..", "README.md"), "utf8");
122
+ const readmeJa = fs.readFileSync(path.join(__dirname, "..", "README.ja.md"), "utf8");
123
+
124
+ for (const doc of [readme, readmeJa]) {
125
+ assert.match(doc, /gwt-macos-universal\.dmg/);
126
+ assert.match(doc, /gwt-windows-x86_64\.msi/);
127
+ assert.match(doc, /gwt-linux-x86_64\.tar\.gz/);
128
+ assert.match(doc, /test:frontend-bundle|node --check crates\/gwt\/web\/app\.js/);
129
+ assert.match(doc, /test:release-flow|bash scripts\/check-release-flow\.sh/);
130
+ }
131
+ });
132
+
70
133
  run("portable tarball extraction installs the unix bundle", () => {
71
134
  const root = fs.mkdtempSync(path.join(os.tmpdir(), "gwt-release-test-"));
72
135
  const sourceDir = path.join(root, "source");
@@ -90,6 +153,10 @@ run("portable tarball extraction installs the unix bundle", () => {
90
153
  });
91
154
 
92
155
  run("portable zip extraction installs the windows bundle", () => {
156
+ if (process.platform !== "win32") {
157
+ return;
158
+ }
159
+
93
160
  const root = fs.mkdtempSync(path.join(os.tmpdir(), "gwt-release-test-"));
94
161
  const sourceDir = path.join(root, "source");
95
162
  const binDir = path.join(root, "bin");
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Jesse Luehrs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9
+ of the Software, and to permit persons to whom the Software is furnished to do
10
+ so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,144 @@
1
+ use crate::term::BufWrite as _;
2
+
3
+ /// Represents a foreground or background color for cells.
4
+ #[derive(Eq, PartialEq, Debug, Copy, Clone, Default)]
5
+ pub enum Color {
6
+ /// The default terminal color.
7
+ #[default]
8
+ Default,
9
+
10
+ /// An indexed terminal color.
11
+ Idx(u8),
12
+
13
+ /// An RGB terminal color. The parameters are (red, green, blue).
14
+ Rgb(u8, u8, u8),
15
+ }
16
+
17
+ const TEXT_MODE_INTENSITY: u8 = 0b0000_0011;
18
+ const TEXT_MODE_BOLD: u8 = 0b0000_0001;
19
+ const TEXT_MODE_DIM: u8 = 0b0000_0010;
20
+ const TEXT_MODE_ITALIC: u8 = 0b0000_0100;
21
+ const TEXT_MODE_UNDERLINE: u8 = 0b0000_1000;
22
+ const TEXT_MODE_INVERSE: u8 = 0b0001_0000;
23
+
24
+ #[derive(Default, Clone, Copy, PartialEq, Eq, Debug)]
25
+ pub struct Attrs {
26
+ pub fgcolor: Color,
27
+ pub bgcolor: Color,
28
+ pub mode: u8,
29
+ }
30
+
31
+ impl Attrs {
32
+ pub fn bold(&self) -> bool {
33
+ self.mode & TEXT_MODE_BOLD != 0
34
+ }
35
+
36
+ pub fn dim(&self) -> bool {
37
+ self.mode & TEXT_MODE_DIM != 0
38
+ }
39
+
40
+ fn intensity(&self) -> u8 {
41
+ self.mode & TEXT_MODE_INTENSITY
42
+ }
43
+
44
+ pub fn set_bold(&mut self) {
45
+ self.mode &= !TEXT_MODE_INTENSITY;
46
+ self.mode |= TEXT_MODE_BOLD;
47
+ }
48
+
49
+ pub fn set_dim(&mut self) {
50
+ self.mode &= !TEXT_MODE_INTENSITY;
51
+ self.mode |= TEXT_MODE_DIM;
52
+ }
53
+
54
+ pub fn set_normal_intensity(&mut self) {
55
+ self.mode &= !TEXT_MODE_INTENSITY;
56
+ }
57
+
58
+ pub fn italic(&self) -> bool {
59
+ self.mode & TEXT_MODE_ITALIC != 0
60
+ }
61
+
62
+ pub fn set_italic(&mut self, italic: bool) {
63
+ if italic {
64
+ self.mode |= TEXT_MODE_ITALIC;
65
+ } else {
66
+ self.mode &= !TEXT_MODE_ITALIC;
67
+ }
68
+ }
69
+
70
+ pub fn underline(&self) -> bool {
71
+ self.mode & TEXT_MODE_UNDERLINE != 0
72
+ }
73
+
74
+ pub fn set_underline(&mut self, underline: bool) {
75
+ if underline {
76
+ self.mode |= TEXT_MODE_UNDERLINE;
77
+ } else {
78
+ self.mode &= !TEXT_MODE_UNDERLINE;
79
+ }
80
+ }
81
+
82
+ pub fn inverse(&self) -> bool {
83
+ self.mode & TEXT_MODE_INVERSE != 0
84
+ }
85
+
86
+ pub fn set_inverse(&mut self, inverse: bool) {
87
+ if inverse {
88
+ self.mode |= TEXT_MODE_INVERSE;
89
+ } else {
90
+ self.mode &= !TEXT_MODE_INVERSE;
91
+ }
92
+ }
93
+
94
+ pub fn write_escape_code_diff(
95
+ &self,
96
+ contents: &mut Vec<u8>,
97
+ other: &Self,
98
+ ) {
99
+ if self != other && self == &Self::default() {
100
+ crate::term::ClearAttrs.write_buf(contents);
101
+ return;
102
+ }
103
+
104
+ let attrs = crate::term::Attrs::default();
105
+
106
+ let attrs = if self.fgcolor == other.fgcolor {
107
+ attrs
108
+ } else {
109
+ attrs.fgcolor(self.fgcolor)
110
+ };
111
+ let attrs = if self.bgcolor == other.bgcolor {
112
+ attrs
113
+ } else {
114
+ attrs.bgcolor(self.bgcolor)
115
+ };
116
+ let attrs = if self.intensity() == other.intensity() {
117
+ attrs
118
+ } else {
119
+ attrs.intensity(match self.intensity() {
120
+ 0 => crate::term::Intensity::Normal,
121
+ TEXT_MODE_BOLD => crate::term::Intensity::Bold,
122
+ TEXT_MODE_DIM => crate::term::Intensity::Dim,
123
+ _ => unreachable!(),
124
+ })
125
+ };
126
+ let attrs = if self.italic() == other.italic() {
127
+ attrs
128
+ } else {
129
+ attrs.italic(self.italic())
130
+ };
131
+ let attrs = if self.underline() == other.underline() {
132
+ attrs
133
+ } else {
134
+ attrs.underline(self.underline())
135
+ };
136
+ let attrs = if self.inverse() == other.inverse() {
137
+ attrs
138
+ } else {
139
+ attrs.inverse(self.inverse())
140
+ };
141
+
142
+ attrs.write_buf(contents);
143
+ }
144
+ }
@@ -0,0 +1,69 @@
1
+ /// This trait is used by the parser to handle extra escape sequences that
2
+ /// don't have an impact on the terminal screen directly.
3
+ pub trait Callbacks {
4
+ /// This callback is called when the terminal requests an audible bell
5
+ /// (typically with `^G`).
6
+ fn audible_bell(&mut self, _: &mut crate::Screen) {}
7
+ /// This callback is called when the terminal requests a visual bell
8
+ /// (typically with `\eg`).
9
+ fn visual_bell(&mut self, _: &mut crate::Screen) {}
10
+ /// This callback is called when the terminal requests a resize
11
+ /// (typically with `\e[8;<rows>;<cols>t`).
12
+ fn resize(&mut self, _: &mut crate::Screen, _request: (u16, u16)) {}
13
+ /// This callback is called when the terminal requests the window title
14
+ /// to be set (typically with `\e]1;<icon_name>\a`)
15
+ fn set_window_icon_name(
16
+ &mut self,
17
+ _: &mut crate::Screen,
18
+ _icon_name: &[u8],
19
+ ) {
20
+ }
21
+ /// This callback is called when the terminal requests the window title
22
+ /// to be set (typically with `\e]2;<title>\a`)
23
+ fn set_window_title(&mut self, _: &mut crate::Screen, _title: &[u8]) {}
24
+ /// This callback is called when the terminal requests data to be copied
25
+ /// to the system clipboard (typically with `\e]52;<ty>;<data>\a`). Note
26
+ /// that `data` will be encoded as base64.
27
+ fn copy_to_clipboard(
28
+ &mut self,
29
+ _: &mut crate::Screen,
30
+ _ty: &[u8],
31
+ _data: &[u8],
32
+ ) {
33
+ }
34
+ /// This callback is called when the terminal requests data to be pasted
35
+ /// from the system clipboard (typically with `\e]52;<ty>;?\a`).
36
+ fn paste_from_clipboard(&mut self, _: &mut crate::Screen, _ty: &[u8]) {}
37
+ /// This callback is called when the terminal receives an escape sequence
38
+ /// which is otherwise not implemented.
39
+ fn unhandled_char(&mut self, _: &mut crate::Screen, _c: char) {}
40
+ /// This callback is called when the terminal receives a control
41
+ /// character which is otherwise not implemented.
42
+ fn unhandled_control(&mut self, _: &mut crate::Screen, _b: u8) {}
43
+ /// This callback is called when the terminal receives an escape sequence
44
+ /// which is otherwise not implemented.
45
+ fn unhandled_escape(
46
+ &mut self,
47
+ _: &mut crate::Screen,
48
+ _i1: Option<u8>,
49
+ _i2: Option<u8>,
50
+ _b: u8,
51
+ ) {
52
+ }
53
+ /// This callback is called when the terminal receives a CSI sequence
54
+ /// (`\e[`) which is otherwise not implemented.
55
+ fn unhandled_csi(
56
+ &mut self,
57
+ _: &mut crate::Screen,
58
+ _i1: Option<u8>,
59
+ _i2: Option<u8>,
60
+ _params: &[&[u16]],
61
+ _c: char,
62
+ ) {
63
+ }
64
+ /// This callback is called when the terminal receives a OSC sequence
65
+ /// (`\e]`) which is otherwise not implemented.
66
+ fn unhandled_osc(&mut self, _: &mut crate::Screen, _params: &[&[u8]]) {}
67
+ }
68
+
69
+ impl Callbacks for () {}