Skip to content

Commit 32f0d51

Browse files
committed
chore(vcs): resolve merge conflicts
1 parent 9624cda commit 32f0d51

File tree

15 files changed

+182
-22
lines changed

15 files changed

+182
-22
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,20 @@ Set WindowBar Colorful
469469
<img width="600" alt="Example of setting the margin" src="https://vhs.charm.sh/vhs-4VgviCu38DbaGtbRzhtOUI.gif">
470470
</picture>
471471

472+
#### Set Window Title
473+
474+
Set a title on the window bar of the terminal window with the `Set WindowTitle` command.
475+
476+
```elixir
477+
Set WindowTitle "Live in the Terminal"
478+
```
479+
480+
<picture>
481+
<source media="(prefers-color-scheme: dark)" srcset="https://vhs.charm.sh/vhs-6s07y8kWtPAC5TBLzxhRfS.gif">
482+
<source media="(prefers-color-scheme: light)" srcset="https://vhs.charm.sh/vhs-6s07y8kWtPAC5TBLzxhRfS.gif">
483+
<img width="600" alt="Example of setting the window title" src="https://vhs.charm.sh/vhs-6s07y8kWtPAC5TBLzxhRfS.gif">
484+
</picture>
485+
472486
#### Set Border Radius
473487

474488
Set the border radius (in pixels) of the terminal window with the `Set BorderRadius` command.

command.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ var Settings = map[string]CommandFunc{
436436
"MarginFill": ExecuteSetMarginFill,
437437
"Margin": ExecuteSetMargin,
438438
"WindowBar": ExecuteSetWindowBar,
439+
"WindowTitle": ExecuteSetWindowTitle,
439440
"WindowBarSize": ExecuteSetWindowBarSize,
440441
"BorderRadius": ExecuteSetBorderRadius,
441442
"WaitPattern": ExecuteSetWaitPattern,
@@ -575,6 +576,7 @@ func ExecuteSetTheme(c parser.Command, v *VHS) error {
575576

576577
v.Options.Video.Style.BackgroundColor = v.Options.Theme.Background
577578
v.Options.Video.Style.WindowBarColor = v.Options.Theme.Background
579+
v.Options.Video.Style.WindowTitleColor = v.Options.Theme.Foreground
578580

579581
return nil
580582
}
@@ -677,6 +679,11 @@ func ExecuteSetWindowBar(c parser.Command, v *VHS) error {
677679
return nil
678680
}
679681

682+
func ExecuteSetWindowTitle(c parser.Command, v *VHS) error {
683+
v.Options.Video.Style.WindowTitle = c.Args
684+
return nil
685+
}
686+
680687
// ExecuteSetWindowBar sets window bar size
681688
func ExecuteSetWindowBarSize(c parser.Command, v *VHS) error {
682689
windowBarSize, err := strconv.Atoi(c.Args)

draw.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ import (
88
"image/png"
99
"math"
1010
"os"
11+
12+
"github.com/golang/freetype"
13+
"github.com/golang/freetype/truetype"
14+
"golang.org/x/image/font"
15+
"golang.org/x/image/font/gofont/goregular"
1116
)
1217

1318
type circle struct {
@@ -233,6 +238,72 @@ const (
233238
barToDotBorderRatio = 5
234239
)
235240

241+
func drawWindowTitle(
242+
dotsSpace,
243+
borderSpace int,
244+
dotsRight bool,
245+
opts StyleOptions,
246+
windowBar *image.RGBA,
247+
) error {
248+
ttf, err := freetype.ParseFont(goregular.TTF)
249+
if err != nil {
250+
return err
251+
}
252+
253+
title := opts.WindowTitle
254+
255+
titleMinX := dotsSpace
256+
titleMaxX := borderSpace
257+
if dotsRight {
258+
titleMinX, titleMaxX = titleMaxX, titleMinX
259+
}
260+
261+
img := image.NewRGBA(
262+
image.Rectangle{
263+
image.Point{
264+
windowBar.Rect.Min.X + titleMinX,
265+
windowBar.Rect.Min.Y,
266+
},
267+
image.Point{
268+
windowBar.Rect.Max.X - titleMaxX,
269+
windowBar.Rect.Max.Y,
270+
},
271+
},
272+
)
273+
274+
fg, _ := parseHexColor(opts.WindowTitleColor)
275+
276+
c := freetype.NewContext()
277+
c.SetDPI(72)
278+
c.SetFont(ttf)
279+
c.SetFontSize(float64(half(opts.WindowBarSize)))
280+
c.SetClip(img.Bounds())
281+
c.SetDst(windowBar)
282+
c.SetSrc(&image.Uniform{fg})
283+
c.SetHinting(font.HintingNone)
284+
285+
fontFace := truetype.NewFace(ttf, &truetype.Options{})
286+
titleTextWidth := font.MeasureString(fontFace, title).Ceil()
287+
titleBarWidth := img.Rect.Max.X - img.Rect.Min.X
288+
289+
// Center-align title text if it will fit, else left-align (truncated by bounds)
290+
var textStartX int
291+
if titleBarWidth >= titleTextWidth {
292+
textStartX = (img.Rect.Max.X - titleTextWidth - titleMaxX) / 2
293+
} else {
294+
textStartX = titleMinX
295+
}
296+
297+
// Font size is half window bar size, thus Y start pos is 0.75 of window bar size
298+
textStartY := int(c.PointToFixed(float64(opts.WindowBarSize)*0.75) >> 6)
299+
300+
pt := freetype.Pt(textStartX, textStartY)
301+
if _, err := c.DrawString(title, pt); err != nil {
302+
return err
303+
}
304+
return nil
305+
}
306+
236307
func makeColorfulBar(termWidth int, termHeight int, isRight bool, opts StyleOptions, targetpng string) error {
237308
// Radius of dots
238309
dotRad := opts.WindowBarSize / barToDotRatio
@@ -305,6 +376,21 @@ func makeColorfulBar(termWidth int, termHeight int, isRight bool, opts StyleOpti
305376
draw.Over,
306377
)
307378

379+
if opts.WindowTitle != "" {
380+
titleDotsSpace := dotGap + dotRad*3 + dotSpace*3
381+
titleBorderSpace := dotGap + dotSpace
382+
383+
if err := drawWindowTitle(
384+
titleDotsSpace,
385+
titleBorderSpace,
386+
isRight,
387+
opts,
388+
img,
389+
); err != nil {
390+
fmt.Println(ErrorStyle.Render(fmt.Sprintf("Couldn't draw window title: %s.", err)))
391+
}
392+
}
393+
308394
f, err := os.Create(targetpng)
309395
if err != nil {
310396
fmt.Println(ErrorStyle.Render("Couldn't draw colorful bar: unable to save file."))
@@ -379,6 +465,21 @@ func makeRingBar(termWidth int, termHeight int, isRight bool, opts StyleOptions,
379465
)
380466
}
381467

468+
if opts.WindowTitle != "" {
469+
titleDotsSpace := ringGap + outerRad*3 + ringSpace*3
470+
titleBorderSpace := ringGap + ringSpace
471+
472+
if err := drawWindowTitle(
473+
titleDotsSpace,
474+
titleBorderSpace,
475+
isRight,
476+
opts,
477+
img,
478+
); err != nil {
479+
fmt.Println(ErrorStyle.Render(fmt.Sprintf("Couldn't draw window title: %s.", err)))
480+
}
481+
}
482+
382483
f, err := os.Create(targetpng)
383484
if err != nil {
384485
fmt.Println(ErrorStyle.Render("Couldn't draw ring bar: unable to save file."))

examples/decorations/decorations.tape

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ Set WindowBarSize 40
1212
Set BorderRadius 8
1313

1414
Type "I can't believe it's not butter."
15-
Sleep 2s
15+
Sleep 2s

examples/demo.tape

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
# Set BorderRadius <number> Set terminal border radius, in pixels.
2626
# Set WindowBar <string> Set window bar type. (one of: Rings, RingsRight, Colorful, ColorfulRight)
2727
# Set WindowBarSize <number> Set window bar size, in pixels. Default is 40.
28+
# Set WindowTitle <string> Set window title. Text color is taken from theme.
2829
# Set TypingSpeed <time> Set the typing speed of the terminal. Default is 50ms.
2930
#
3031
# Sleep:

examples/fixtures/all.tape

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Set TypingSpeed .1
2222
Set LoopOffset 60.4
2323
Set LoopOffset 20.99%
2424
Set CursorBlink false
25+
Set WindowTitle "Hello, world!"
2526

2627
# Sleep:
2728
Sleep 1
22.9 KB
Loading
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Output examples/settings/set-window-title.gif
2+
3+
Set FontSize 25
4+
Set Width 800
5+
Set Height 400
6+
Set Padding 20
7+
8+
Set WindowBar Colorful
9+
Set WindowTitle "Live in the Terminal"
10+
Set WindowBarSize 40
11+
12+
Type "This terminal window has a title."
13+
Sleep 2s

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ require (
1515
github.com/charmbracelet/wish v1.4.3
1616
github.com/creack/pty v1.1.23
1717
github.com/go-rod/rod v0.116.2
18+
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
1819
github.com/hashicorp/go-version v1.7.0
1920
github.com/mattn/go-isatty v0.0.20
2021
github.com/mattn/go-runewidth v0.0.16
@@ -24,6 +25,7 @@ require (
2425
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a
2526
github.com/spf13/cobra v1.8.1
2627
golang.org/x/crypto v0.28.0
28+
golang.org/x/image v0.18.0
2729
golang.org/x/term v0.25.0
2830
)
2931

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi
6161
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
6262
github.com/go-rod/rod v0.116.2 h1:A5t2Ky2A+5eD/ZJQr1EfsQSe5rms5Xof/qj296e+ZqA=
6363
github.com/go-rod/rod v0.116.2/go.mod h1:H+CMO9SCNc2TJ2WfrG+pKhITz57uGNYU43qYHh438Mg=
64+
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
65+
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
6466
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
6567
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
6668
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
@@ -136,6 +138,8 @@ golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
136138
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
137139
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
138140
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
141+
golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ=
142+
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
139143
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
140144
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
141145
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=

0 commit comments

Comments
 (0)