Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(#89): added input file as window title #107

Draft
wants to merge 26 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
808ac7a
feat(#89): added input file as window title
AlejandroSuero Jun 8, 2024
fbc39f8
fix: removed else statment when fatal
AlejandroSuero Jun 9, 2024
8e465d7
feat(svg): center text and improved error message
AlejandroSuero Jun 10, 2024
09a8bf8
feat(configurations): added `title: auto` to `full.json`
AlejandroSuero Jun 10, 2024
0ec729a
feat(config): modified `config.Title` to be a string
AlejandroSuero Jun 10, 2024
822f84c
feat(interactive): modified to work with `config.Title` as string
AlejandroSuero Jun 10, 2024
32641ce
feat(main): modified to work with `config.Title` as string
AlejandroSuero Jun 10, 2024
095d65c
test(window.title): test suite for `--window.title`
AlejandroSuero Jun 10, 2024
3cd9296
docs: updated `README.md` with new usage of `config.Title` as string
AlejandroSuero Jun 10, 2024
03aff1a
feat(svg): early return
AlejandroSuero Jun 10, 2024
ad05ab8
feat(golden): modified images when `make golden`
AlejandroSuero Jun 10, 2024
0c51a1c
docs(README): better demo and better warning
AlejandroSuero Jun 10, 2024
c087cce
test(freeze): using `t.Cleanup` and checking for child elements
AlejandroSuero Jun 10, 2024
8d2ab0a
feat(main): use `} else if {`
AlejandroSuero Jun 10, 2024
014f87d
feat: added title position and title text
AlejandroSuero Jun 11, 2024
de16e84
feat: added title position logic
AlejandroSuero Jun 11, 2024
716540c
feat: added title positions
AlejandroSuero Jun 11, 2024
89fb933
test(golden): `make golden` after changes
AlejandroSuero Jun 11, 2024
9341f16
refactor(title): moved from `svg.go` to `main.go`
AlejandroSuero Jun 11, 2024
af731cf
docs: updated `--title` usage
AlejandroSuero Jun 11, 2024
a2ba0f3
fix: removed `group:"Window"` from `Title`
AlejandroSuero Jun 11, 2024
406de92
refactor: switch and value usage
AlejandroSuero Jun 12, 2024
11b73ac
refactor: use constants for positions
AlejandroSuero Jun 12, 2024
7a46616
feat: increase font size a bit and improved center with controls
AlejandroSuero Jun 12, 2024
bb40c9b
fix: simply return err
AlejandroSuero Jun 12, 2024
244c20c
Merge branch 'main' into feature/show-filename-when-controls
AlejandroSuero Sep 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ Screenshots can be customized with `--flags` or [Configuration](#configuration)
- [`-t`](#theme), [`--theme`](#theme): Theme to use for syntax highlighting.
- [`-w`](#window), [`--window`](#window): Display window controls.
- [`-H`](#height), [`--height`](#height): Height of terminal window.
- [`--window.title`](#window-title): Display input file as title when window controls are displayed.
AlejandroSuero marked this conversation as resolved.
Show resolved Hide resolved
AlejandroSuero marked this conversation as resolved.
Show resolved Hide resolved
- [`--border.width`](#border-width): Border width thickness.
- [`--border.color`](#border-width): Border color.
- [`--shadow.blur`](#shadow): Shadow Gaussian Blur.
Expand Down Expand Up @@ -216,6 +217,24 @@ freeze artichoke.hs --window
<img alt="output of freeze command, Haskell code block with window controls applied" src="./test/golden/svg/window.svg" width="600" />
</a>

#### Window Title

Display the input file as the title of the window if `--window.title` is not passed in the arguments (`--window.title=auto` as default).

Display a custom title if `--window.title` is passed in the arguments (`--window.title="custom title"`).

Don't display the title if `--window.title` is passed in the arguments as empty string (`--window.title=""`).
AlejandroSuero marked this conversation as resolved.
Show resolved Hide resolved

```bash
freeze artichoke.hs --window --window.title "My artichoke code"
```

<img alt="output of freeze command, Haskell code block with window title applied" src="./test/golden/svg/title.svg" width="600" />

> [!WARNING]
>
> The **title** can only be supported when using **window** mode (`--window=true`).

### Background

Set the background color of the terminal window.
Expand Down
6 changes: 6 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type Config struct {
Margin []float64 `json:"margin" help:"Apply margin to the window." short:"m" placeholder:"0" group:"Window"`
Padding []float64 `json:"padding" help:"Apply padding to the code." short:"p" placeholder:"0" group:"Window"`
Window bool `json:"window" help:"Display window controls." group:"Window"`
Title Title `json:"title" embed:"" prefix:"title." group:"Window"`
Width float64 `json:"width" help:"Width of terminal window." short:"W" group:"Window"`
Height float64 `json:"height" help:"Height of terminal window." short:"H" group:"Window"`

Expand Down Expand Up @@ -49,6 +50,11 @@ type Config struct {
ShowLineNumbers bool `json:"show_line_numbers" help:"" group:"Line" placeholder:"false"`
}

type Title struct {
Text string `json:"title" help:"Display window title. {{--title.text=auto}} as default for input filename." group:"Window" default:"auto"`
Position string `json:"position" help:"Position of window title, one of {{left}}, {{center}}, or {{right}}. {{--title.position=center}} as default." group:"Window" default:"center"`
AlejandroSuero marked this conversation as resolved.
Show resolved Hide resolved
}

// Shadow is the configuration options for a drop shadow.
type Shadow struct {
Blur float64 `json:"blur" help:"Shadow Gaussian Blur." placeholder:"0"`
Expand Down
6 changes: 5 additions & 1 deletion configurations/full.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
{
"window": true,
"title": {
"text": "auto",
"position": "center"
},
"theme": "charm",
"border": {
"radius": 8,
Expand Down Expand Up @@ -30,4 +34,4 @@
"ligatures": true
},
"line_height": 1.2
}
}
62 changes: 62 additions & 0 deletions freeze_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"testing"

"github.com/aymanbagabas/go-udiff"
"github.com/beevik/etree"
)

const binary = "./test/freeze-test"
Expand Down Expand Up @@ -104,6 +105,62 @@ func TestFreezeErrorFileMissing(t *testing.T) {
}
}

func TestFreezeWindowTitleFilename(t *testing.T) {
output := "artichoke-default-title.svg"
t.Cleanup(func() { os.Remove(output) })
testTitle := "artichoke.hs"
cmd := exec.Command(binary, "test/input/artichoke.hs", "--output", output, "--window")
err := cmd.Run()

if err != nil {
t.Fatal("unexpected error", err)
}

doc := etree.NewDocument()
err = doc.ReadFromFile(output)
if err != nil {
t.Fatal("unexpected error", err)
}
childs := doc.ChildElements()
if len(childs) == 0 {
t.Fatal("no child elements")
}
lastChild := childs[len(childs)-1]
AlejandroSuero marked this conversation as resolved.
Show resolved Hide resolved
got := lastChild.FindElement("text").Text()

if got != testTitle {
t.Fatalf("expected %s to be %s", got, testTitle)
}
}

func TestFreezeCustomWindowTitle(t *testing.T) {
output := "artichoke-custom-title.svg"
t.Cleanup(func() { os.Remove(output) })
testTitle := "custom-test title"
cmd := exec.Command(binary, "test/input/artichoke.hs", "--output", output, "--title.text", testTitle, "--window")
err := cmd.Run()

if err != nil {
t.Fatal("unexpected error", err)
}

doc := etree.NewDocument()
err = doc.ReadFromFile(output)
if err != nil {
t.Fatal("unexpected error", err)
}
childs := doc.ChildElements()
if len(childs) == 0 {
t.Fatal("no child elements")
}
lastChild := childs[len(childs)-1]
got := lastChild.FindElement("text").Text()

if got != testTitle {
t.Fatalf("expected %s to be %s", got, testTitle)
}
}

func TestFreezeConfigurations(t *testing.T) {
tests := []struct {
input string
Expand Down Expand Up @@ -258,6 +315,11 @@ func TestFreezeConfigurations(t *testing.T) {
flags: []string{"--wrap", "80", "--width", "600"},
output: "wrap",
},
{
input: "test/input/artichoke.hs",
flags: []string{"--border.radius", "8", "--window", "--title.text", "My artichoke code"},
output: "title",
},
}

err := os.RemoveAll("test/output/svg")
Expand Down
11 changes: 11 additions & 0 deletions interactive.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,17 @@ func runForm(config *Config) (*Config, error) {
Inline(true).
Value(&config.Window),

huh.NewInput().Title("Title text").
Placeholder("auto").
Inline(true).
Prompt("").
Value(&config.Title.Text),

huh.NewSelect[string]().Title("Title position").
Inline(true).
Options(huh.NewOptions("left", "center", "right")...).
Value(&config.Title.Position),

huh.NewNote().Title("Font"),

huh.NewInput().Title("Font Family ").
Expand Down
26 changes: 25 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,10 +287,34 @@ func main() {
}

if config.Window {
windowControls := svg.NewWindowControls(5.5*float64(scale), 19.0*scale, 12.0*scale)
x := 19.0 * scale
y := 12.0 * scale
windowControls, controlsWidth := svg.NewWindowControls(5.5*float64(scale), x, y)
svg.Move(windowControls, float64(config.Margin[left]), float64(config.Margin[top]))
image.AddChild(windowControls)
config.Padding[top] += (15 * scale)
if config.Title.Text != "" {
titleText := config.Title.Text
if config.Title.Text == "auto" {
titleText = filepath.Base(config.Input)
}
my := float64(config.Margin[top]) + y
ml := float64(config.Margin[left]) + x + controlsWidth
mr := float64(config.Margin[right]) + x
// [0] left, [1] center, [2] right, [3] top
titlePos := []float64{ml, imageWidth / 2, imageWidth - mr, my}
AlejandroSuero marked this conversation as resolved.
Show resolved Hide resolved
title, err := svg.NewWindowTitle(titlePos, config.Title.Position, config.Font.Size*float64(scale), config.Font.Family, titleText, s)
if err != nil {
printErrorFatal("Unable to add title", err)
AlejandroSuero marked this conversation as resolved.
Show resolved Hide resolved
}
image.AddChild(title)
}
} else if config.Title.Text != "auto" {
err := errors.New("Title is not supported when not using a window controls")
printErrorFatal("Unable to add title", err)
} else if config.Title.Position != "center" {
AlejandroSuero marked this conversation as resolved.
Show resolved Hide resolved
err := errors.New("Title position is not supported when not using a window controls")
printErrorFatal("Unable to add title", err)
}

if config.Border.Radius > 0 {
Expand Down
44 changes: 42 additions & 2 deletions svg/svg.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package svg

import (
"errors"
"fmt"
"strconv"
"strings"

"github.com/alecthomas/chroma/v2"
"github.com/beevik/etree"
)

Expand Down Expand Up @@ -82,7 +84,7 @@ const (
)

// NewWindowControls returns a colorful window bar element.
func NewWindowControls(r float64, x, y float64) *etree.Element {
func NewWindowControls(r float64, x, y float64) (*etree.Element, float64) {
bar := etree.NewElement("svg")
for i, color := range []string{red, yellow, green} {
circle := etree.NewElement("circle")
Expand All @@ -92,7 +94,45 @@ func NewWindowControls(r float64, x, y float64) *etree.Element {
circle.CreateAttr("fill", color)
bar.AddChild(circle)
}
return bar
controlsWidth := float64(len(bar.ChildElements()))*float64(x) + float64(r)*2
AlejandroSuero marked this conversation as resolved.
Show resolved Hide resolved
return bar, controlsWidth
}

// NewWindowTitle returns a title element with the given text.
func NewWindowTitle(positions []float64, position string, fs float64, ff, text string, s *chroma.Style) (*etree.Element, error) {
AlejandroSuero marked this conversation as resolved.
Show resolved Hide resolved
if text == "" || text == "-" {
AlejandroSuero marked this conversation as resolved.
Show resolved Hide resolved
return nil, errors.New("Invalid title provided")
}
if position != "left" && position != "center" && position != "right" {
return nil, errors.New("Invalid title position. Must be one of \"left\", \"center\", or \"right\"")
}
// positions[0] left, [1] center, [2] right, [3] top
x := 0.0
y := positions[3]
var anchor string
switch position {
case "left":
x = positions[0]
anchor = "start"
break
case "center":
x = positions[1]
anchor = "middle"
break
case "right":
x = positions[2]
anchor = "end"
break
}
input := etree.NewElement("text")
input.CreateAttr("font-size", fmt.Sprintf("%.2fpx", fs))
input.CreateAttr("fill", s.Get(chroma.Text).Colour.String())
input.CreateAttr("font-family", ff)
input.CreateAttr("text-anchor", anchor)
input.CreateAttr("alignment-baseline", "middle")
input.SetText(text)
Move(input, float64(x), float64(y))
return input, nil
}

// SetDimensions sets the width and height of the given element.
Expand Down
6 changes: 5 additions & 1 deletion test/configurations/full.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
{
"window": true,
"title": {
"text": "auto",
"position": "center"
},
"theme": "charm",
"border": {
"radius": 8,
Expand All @@ -24,4 +28,4 @@
"size": 14
},
"line_height": 1.2
}
}
2 changes: 1 addition & 1 deletion test/golden/svg/artichoke-full.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion test/golden/svg/border-width.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion test/golden/svg/dimensions-config.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion test/golden/svg/eza.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion test/golden/svg/lines.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion test/golden/svg/margin.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading