From 808ac7aae4285771e98fdc523e9fd1e57a2b9b65 Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Sun, 9 Jun 2024 00:54:15 +0200 Subject: [PATCH 01/25] feat(#89): added input file as window title --- README.md | 11 +++++++++++ config.go | 1 + freeze_test.go | 5 +++++ interactive.go | 4 ++++ main.go | 8 ++++++++ svg/svg.go | 16 ++++++++++++++++ test/golden/svg/title.svg | 29 +++++++++++++++++++++++++++++ 7 files changed, 74 insertions(+) create mode 100644 test/golden/svg/title.svg diff --git a/README.md b/README.md index 533a1de..7c846c9 100644 --- a/README.md +++ b/README.md @@ -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. - [`--border.width`](#border-width): Border width thickness. - [`--border.color`](#border-width): Border color. - [`--shadow.blur`](#shadow): Shadow Gaussian Blur. @@ -216,6 +217,16 @@ freeze artichoke.hs --window output of freeze command, Haskell code block with window controls applied +#### Window Title + +Display the input file as the title of the window. + +```bash +freeze artichoke.hs --window --window.title +``` + +output of freeze command, Haskell code block with window title applied + ### Background Set the background color of the terminal window. diff --git a/config.go b/config.go index cd572e6..33585fa 100644 --- a/config.go +++ b/config.go @@ -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 bool `json:"title" help:"Display input file as title." prefix:"window." group:"Window" hidden:""` 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"` diff --git a/freeze_test.go b/freeze_test.go index 06b4e43..d6c8674 100644 --- a/freeze_test.go +++ b/freeze_test.go @@ -258,6 +258,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", "--window.title"}, + output: "title", + }, } err := os.RemoveAll("test/output/svg") diff --git a/interactive.go b/interactive.go index e7916cf..49484ed 100644 --- a/interactive.go +++ b/interactive.go @@ -103,6 +103,10 @@ func runForm(config *Config) (*Config, error) { Inline(true). Value(&config.Window), + huh.NewConfirm().Title("Title"). + Inline(true). + Value(&config.Title), + huh.NewNote().Title("Font"), huh.NewInput().Title("Font Family "). diff --git a/main.go b/main.go index 56f9892..333f70b 100644 --- a/main.go +++ b/main.go @@ -291,6 +291,14 @@ func main() { svg.Move(windowControls, float64(config.Margin[left]), float64(config.Margin[top])) image.AddChild(windowControls) config.Padding[top] += (15 * scale) + if config.Title { + title, err := svg.NewWindowTitle(float64(config.Margin[left]+imageWidth/2), float64(config.Margin[top]+config.Font.Size*float64(scale)), scale, config.Font.Size, config.Font.Family, config.Input, s) + if err != nil { + printErrorFatal("Unable to add title", err) + } else { + image.AddChild(title) + } + } } if config.Border.Radius > 0 { diff --git a/svg/svg.go b/svg/svg.go index a12f9cb..afd87b6 100644 --- a/svg/svg.go +++ b/svg/svg.go @@ -1,10 +1,12 @@ package svg import ( + "errors" "fmt" "strconv" "strings" + "github.com/alecthomas/chroma/v2" "github.com/beevik/etree" ) @@ -95,6 +97,20 @@ func NewWindowControls(r float64, x, y float64) *etree.Element { return bar } +func NewWindowTitle(x, y, scale, fs float64, ff, text string, s *chroma.Style) (*etree.Element, error) { + if text != "" && text != "-" { + input := etree.NewElement("text") + input.CreateAttr("font-size", fmt.Sprintf("%.2fpx", fs*float64(scale))) + input.CreateAttr("fill", s.Get(chroma.Text).Colour.String()) + input.CreateAttr("font-family", ff) + input.SetText(text) + Move(input, float64(x), float64(y)) + return input, nil + } + err := errors.New("no text") + return nil, err +} + // SetDimensions sets the width and height of the given element. func SetDimensions(element *etree.Element, width, height float64) { widthAttr := element.SelectAttr("width") diff --git a/test/golden/svg/title.svg b/test/golden/svg/title.svg new file mode 100644 index 0000000..6a87453 --- /dev/null +++ b/test/golden/svg/title.svg @@ -0,0 +1,29 @@ + + + + + +module Main where + +import Data.Function ( (&) ) +import Data.List ( intercalate ) + +hello :: String -> String +hello s = +  "Hello, " ++ s ++ "." + +main :: IO () +main = +  map hello [ "artichoke", "alcachofa" ] & intercalate "\n" & putStrLn + +-- Alcachofa, if you were wondering, is artichoke in Spanish. + + +test/input/artichoke.hs From fbc39f8e3080f3cbc166c9a9eeea8ec940ebe063 Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Sun, 9 Jun 2024 14:00:06 +0200 Subject: [PATCH 02/25] fix: removed else statment when fatal --- main.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/main.go b/main.go index 333f70b..e0b488d 100644 --- a/main.go +++ b/main.go @@ -295,9 +295,8 @@ func main() { title, err := svg.NewWindowTitle(float64(config.Margin[left]+imageWidth/2), float64(config.Margin[top]+config.Font.Size*float64(scale)), scale, config.Font.Size, config.Font.Family, config.Input, s) if err != nil { printErrorFatal("Unable to add title", err) - } else { - image.AddChild(title) } + image.AddChild(title) } } From 8e465d73a5cc0649351489c502dc431074dfd2e7 Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Mon, 10 Jun 2024 12:54:22 +0200 Subject: [PATCH 03/25] feat(svg): center text and improved error message --- svg/svg.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/svg/svg.go b/svg/svg.go index afd87b6..1bcc7f5 100644 --- a/svg/svg.go +++ b/svg/svg.go @@ -103,11 +103,14 @@ func NewWindowTitle(x, y, scale, fs float64, ff, text string, s *chroma.Style) ( input.CreateAttr("font-size", fmt.Sprintf("%.2fpx", fs*float64(scale))) input.CreateAttr("fill", s.Get(chroma.Text).Colour.String()) input.CreateAttr("font-family", ff) + input.CreateAttr("text-anchor", "middle") + input.CreateAttr("alignment-baseline", "middle") + input.CreateAttr("dominant-baseline", "middle") input.SetText(text) Move(input, float64(x), float64(y)) return input, nil } - err := errors.New("no text") + err := errors.New("No valid text provided") return nil, err } From 09a8bf8681ddd0a501245a6db4b980c80c20169f Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Mon, 10 Jun 2024 12:55:04 +0200 Subject: [PATCH 04/25] feat(configurations): added `title: auto` to `full.json` --- configurations/full.json | 3 ++- test/configurations/full.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/configurations/full.json b/configurations/full.json index 40d5131..561c51b 100644 --- a/configurations/full.json +++ b/configurations/full.json @@ -1,5 +1,6 @@ { "window": true, + "title": "auto", "theme": "charm", "border": { "radius": 8, @@ -30,4 +31,4 @@ "ligatures": true }, "line_height": 1.2 -} \ No newline at end of file +} diff --git a/test/configurations/full.json b/test/configurations/full.json index bded6b0..659aa62 100644 --- a/test/configurations/full.json +++ b/test/configurations/full.json @@ -1,5 +1,6 @@ { "window": true, + "title": "auto", "theme": "charm", "border": { "radius": 8, @@ -24,4 +25,4 @@ "size": 14 }, "line_height": 1.2 -} \ No newline at end of file +} From 0ec729a6b15314041f8241f8c01291d94db43760 Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Mon, 10 Jun 2024 12:56:35 +0200 Subject: [PATCH 05/25] feat(config): modified `config.Title` to be a string --- config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.go b/config.go index 33585fa..654c2da 100644 --- a/config.go +++ b/config.go @@ -22,7 +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 bool `json:"title" help:"Display input file as title." prefix:"window." group:"Window" hidden:""` + Title string `json:"title,omitempty" help:"Display window title. {{--window.title=auto}} as default for input filename." prefix:"window." group:"Window" default:"auto"` 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"` From 822f84c7cf6f54de4608b92f349b6491f484507c Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Mon, 10 Jun 2024 12:57:29 +0200 Subject: [PATCH 06/25] feat(interactive): modified to work with `config.Title` as string --- interactive.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interactive.go b/interactive.go index 49484ed..b6ea4db 100644 --- a/interactive.go +++ b/interactive.go @@ -103,8 +103,10 @@ func runForm(config *Config) (*Config, error) { Inline(true). Value(&config.Window), - huh.NewConfirm().Title("Title"). + huh.NewInput().Title("Title"). + Placeholder("auto"). Inline(true). + Prompt(""). Value(&config.Title), huh.NewNote().Title("Font"), From 32641ce03887a68b0b5cdbe0e8abf82edd216d08 Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Mon, 10 Jun 2024 13:02:36 +0200 Subject: [PATCH 07/25] feat(main): modified to work with `config.Title` as string If `config.Window = false` reports an error for invalid usage. If `config.Window = true` if `config.Title` provided and diferent from `"auto"` use it as title. If `config.Window = true` and `config.Title` not provided or is `"auto"`, use filename as title. If `config.Window = true` and `config.Title` is empty string, don't set title. --- main.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index e0b488d..7e65f34 100644 --- a/main.go +++ b/main.go @@ -291,13 +291,24 @@ func main() { svg.Move(windowControls, float64(config.Margin[left]), float64(config.Margin[top])) image.AddChild(windowControls) config.Padding[top] += (15 * scale) - if config.Title { - title, err := svg.NewWindowTitle(float64(config.Margin[left]+imageWidth/2), float64(config.Margin[top]+config.Font.Size*float64(scale)), scale, config.Font.Size, config.Font.Family, config.Input, s) + if config.Title != "" { + titleText := config.Title + if config.Title == "auto" { + titleText = filepath.Base(config.Input) + } + x := float64(config.Margin[left] + imageWidth/2) + y := float64(config.Margin[top] + config.Font.Size*float64(scale)) + title, err := svg.NewWindowTitle(x, y, scale, config.Font.Size, config.Font.Family, titleText, s) if err != nil { printErrorFatal("Unable to add title", err) } image.AddChild(title) } + } else { + if config.Title != "auto" { + err := errors.New("Title is not supported when not using a window controls") + printErrorFatal("Unable to add title", err) + } } if config.Border.Radius > 0 { From 095d65c0321a53730821f4d4519bb3df9026d27c Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Mon, 10 Jun 2024 13:04:52 +0200 Subject: [PATCH 08/25] test(window.title): test suite for `--window.title` If `--window.title` not provided should use `config.Input`'s filename as title. If `--window.title` provided should use `config.Title`'s input as title. --- freeze_test.go | 52 ++++++++++++++++++++++- test/golden/svg/artichoke-full.svg | 2 +- test/golden/svg/border-width.svg | 2 +- test/golden/svg/dimensions-config.svg | 2 +- test/golden/svg/eza.svg | 2 +- test/golden/svg/lines.svg | 2 +- test/golden/svg/margin.svg | 2 +- test/golden/svg/overflow-line-numbers.svg | 2 +- test/golden/svg/overflow.svg | 2 +- test/golden/svg/padding.svg | 2 +- test/golden/svg/shadow.svg | 2 +- test/golden/svg/title.svg | 2 +- test/golden/svg/window.svg | 2 +- 13 files changed, 63 insertions(+), 13 deletions(-) diff --git a/freeze_test.go b/freeze_test.go index d6c8674..bdfb985 100644 --- a/freeze_test.go +++ b/freeze_test.go @@ -10,6 +10,7 @@ import ( "testing" "github.com/aymanbagabas/go-udiff" + "github.com/beevik/etree" ) const binary = "./test/freeze-test" @@ -104,6 +105,55 @@ func TestFreezeErrorFileMissing(t *testing.T) { } } +func TestFreezeWindowTitleFilename(t *testing.T) { + output := "artichoke-default-title.svg" + defer 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() + lastChild := childs[len(childs)-1] + 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" + defer os.Remove(output) + testTitle := "custom-test title" + cmd := exec.Command(binary, "test/input/artichoke.hs", "--output", output, "--window.title", 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) + } + lastChild := doc.ChildElements()[len(doc.ChildElements())-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 @@ -260,7 +310,7 @@ func TestFreezeConfigurations(t *testing.T) { }, { input: "test/input/artichoke.hs", - flags: []string{"--border.radius", "8", "--window", "--window.title"}, + flags: []string{"--border.radius", "8", "--window", "--window.title", "auto"}, output: "title", }, } diff --git a/test/golden/svg/artichoke-full.svg b/test/golden/svg/artichoke-full.svg index c5e9984..48e8758 100644 --- a/test/golden/svg/artichoke-full.svg +++ b/test/golden/svg/artichoke-full.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. - +artichoke.hs diff --git a/test/golden/svg/border-width.svg b/test/golden/svg/border-width.svg index 98bbb13..6a84555 100644 --- a/test/golden/svg/border-width.svg +++ b/test/golden/svg/border-width.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. - +artichoke.hs diff --git a/test/golden/svg/dimensions-config.svg b/test/golden/svg/dimensions-config.svg index 2478105..eab537f 100644 --- a/test/golden/svg/dimensions-config.svg +++ b/test/golden/svg/dimensions-config.svg @@ -19,4 +19,4 @@ hello s = - +artichoke.hs diff --git a/test/golden/svg/eza.svg b/test/golden/svg/eza.svg index 4336c3e..7fb0614 100644 --- a/test/golden/svg/eza.svg +++ b/test/golden/svg/eza.svg @@ -12,4 +12,4 @@ ansi.go cut_test.go go.mod main.go style.goconfig.go error.go go.sum Makefile svgconfig_test.go font help.go png.go tapesconfigurations font.go input pty.go testcut.go freeze_test.go interactive.go README.md - +eza.ansi diff --git a/test/golden/svg/lines.svg b/test/golden/svg/lines.svg index 186a291..c1049a8 100644 --- a/test/golden/svg/lines.svg +++ b/test/golden/svg/lines.svg @@ -16,4 +16,4 @@ 7 hello s = 8   "Hello, " ++ s ++ "." - +artichoke.hs diff --git a/test/golden/svg/margin.svg b/test/golden/svg/margin.svg index 956194b..949e928 100644 --- a/test/golden/svg/margin.svg +++ b/test/golden/svg/margin.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. - +artichoke.hs diff --git a/test/golden/svg/overflow-line-numbers.svg b/test/golden/svg/overflow-line-numbers.svg index b5461c9..5e43374 100644 --- a/test/golden/svg/overflow-line-numbers.svg +++ b/test/golden/svg/overflow-line-numbers.svg @@ -120,4 +120,4 @@ 108     secret_name: FURY_TOKEN - +goreleaser-full.yml diff --git a/test/golden/svg/overflow.svg b/test/golden/svg/overflow.svg index 6f97838..85f4664 100644 --- a/test/golden/svg/overflow.svg +++ b/test/golden/svg/overflow.svg @@ -55,4 +55,4 @@     goarch: - +goreleaser-full.yml diff --git a/test/golden/svg/padding.svg b/test/golden/svg/padding.svg index 0b20d97..aa0e346 100644 --- a/test/golden/svg/padding.svg +++ b/test/golden/svg/padding.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. - +artichoke.hs diff --git a/test/golden/svg/shadow.svg b/test/golden/svg/shadow.svg index ad66d04..87d1179 100644 --- a/test/golden/svg/shadow.svg +++ b/test/golden/svg/shadow.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. - +artichoke.hs diff --git a/test/golden/svg/title.svg b/test/golden/svg/title.svg index 6a87453..450ead4 100644 --- a/test/golden/svg/title.svg +++ b/test/golden/svg/title.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. -test/input/artichoke.hs +artichoke.hs diff --git a/test/golden/svg/window.svg b/test/golden/svg/window.svg index b64e6ae..450ead4 100644 --- a/test/golden/svg/window.svg +++ b/test/golden/svg/window.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. - +artichoke.hs From 3cd9296591c00012f6b268e451178aa2934beabc Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Mon, 10 Jun 2024 13:10:46 +0200 Subject: [PATCH 09/25] docs: updated `README.md` with new usage of `config.Title` as string --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7c846c9..be6e2db 100644 --- a/README.md +++ b/README.md @@ -219,14 +219,22 @@ freeze artichoke.hs --window #### Window Title -Display the input file as the title of the window. +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=""`). ```bash -freeze artichoke.hs --window --window.title +freeze artichoke.hs --window ``` output of freeze command, Haskell code block with window title applied +> [!WARNING] +> +> `--window.title` is not supported when using `--window=false`. + ### Background Set the background color of the terminal window. From 03aff1a908bbb8452e6d4bb13c675eb9481546f4 Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Mon, 10 Jun 2024 21:52:17 +0200 Subject: [PATCH 10/25] feat(svg): early return --- svg/svg.go | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/svg/svg.go b/svg/svg.go index 1bcc7f5..a75ac20 100644 --- a/svg/svg.go +++ b/svg/svg.go @@ -98,20 +98,19 @@ func NewWindowControls(r float64, x, y float64) *etree.Element { } func NewWindowTitle(x, y, scale, fs float64, ff, text string, s *chroma.Style) (*etree.Element, error) { - if text != "" && text != "-" { - input := etree.NewElement("text") - input.CreateAttr("font-size", fmt.Sprintf("%.2fpx", fs*float64(scale))) - input.CreateAttr("fill", s.Get(chroma.Text).Colour.String()) - input.CreateAttr("font-family", ff) - input.CreateAttr("text-anchor", "middle") - input.CreateAttr("alignment-baseline", "middle") - input.CreateAttr("dominant-baseline", "middle") - input.SetText(text) - Move(input, float64(x), float64(y)) - return input, nil + if text == "" || text == "-" { + return nil, errors.New("Invalid title provided") } - err := errors.New("No valid text provided") - return nil, err + input := etree.NewElement("text") + input.CreateAttr("font-size", fmt.Sprintf("%.2fpx", fs*float64(scale))) + input.CreateAttr("fill", s.Get(chroma.Text).Colour.String()) + input.CreateAttr("font-family", ff) + input.CreateAttr("text-anchor", "middle") + input.CreateAttr("alignment-baseline", "middle") + input.CreateAttr("dominant-baseline", "middle") + input.SetText(text) + Move(input, float64(x), float64(y)) + return input, nil } // SetDimensions sets the width and height of the given element. From ad05ab8253dde4b7513694681fc777b9a1772fb1 Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Mon, 10 Jun 2024 21:52:43 +0200 Subject: [PATCH 11/25] feat(golden): modified images when `make golden` --- test/golden/svg/artichoke-full.svg | 2 +- test/golden/svg/border-width.svg | 2 +- test/golden/svg/dimensions-config.svg | 2 +- test/golden/svg/eza.svg | 2 +- test/golden/svg/lines.svg | 2 +- test/golden/svg/margin.svg | 2 +- test/golden/svg/overflow-line-numbers.svg | 2 +- test/golden/svg/overflow.svg | 2 +- test/golden/svg/padding.svg | 2 +- test/golden/svg/shadow.svg | 2 +- test/golden/svg/title.svg | 2 +- test/golden/svg/window.svg | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/test/golden/svg/artichoke-full.svg b/test/golden/svg/artichoke-full.svg index 48e8758..4551046 100644 --- a/test/golden/svg/artichoke-full.svg +++ b/test/golden/svg/artichoke-full.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. -artichoke.hs +artichoke.hs diff --git a/test/golden/svg/border-width.svg b/test/golden/svg/border-width.svg index 6a84555..dbc713f 100644 --- a/test/golden/svg/border-width.svg +++ b/test/golden/svg/border-width.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. -artichoke.hs +artichoke.hs diff --git a/test/golden/svg/dimensions-config.svg b/test/golden/svg/dimensions-config.svg index eab537f..2e85d46 100644 --- a/test/golden/svg/dimensions-config.svg +++ b/test/golden/svg/dimensions-config.svg @@ -19,4 +19,4 @@ hello s = -artichoke.hs +artichoke.hs diff --git a/test/golden/svg/eza.svg b/test/golden/svg/eza.svg index 7fb0614..b5db97f 100644 --- a/test/golden/svg/eza.svg +++ b/test/golden/svg/eza.svg @@ -12,4 +12,4 @@ ansi.go cut_test.go go.mod main.go style.goconfig.go error.go go.sum Makefile svgconfig_test.go font help.go png.go tapesconfigurations font.go input pty.go testcut.go freeze_test.go interactive.go README.md -eza.ansi +eza.ansi diff --git a/test/golden/svg/lines.svg b/test/golden/svg/lines.svg index c1049a8..adcac25 100644 --- a/test/golden/svg/lines.svg +++ b/test/golden/svg/lines.svg @@ -16,4 +16,4 @@ 7 hello s = 8   "Hello, " ++ s ++ "." -artichoke.hs +artichoke.hs diff --git a/test/golden/svg/margin.svg b/test/golden/svg/margin.svg index 949e928..ff91f62 100644 --- a/test/golden/svg/margin.svg +++ b/test/golden/svg/margin.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. -artichoke.hs +artichoke.hs diff --git a/test/golden/svg/overflow-line-numbers.svg b/test/golden/svg/overflow-line-numbers.svg index 5e43374..e4b3387 100644 --- a/test/golden/svg/overflow-line-numbers.svg +++ b/test/golden/svg/overflow-line-numbers.svg @@ -120,4 +120,4 @@ 108     secret_name: FURY_TOKEN -goreleaser-full.yml +goreleaser-full.yml diff --git a/test/golden/svg/overflow.svg b/test/golden/svg/overflow.svg index 85f4664..2daaa12 100644 --- a/test/golden/svg/overflow.svg +++ b/test/golden/svg/overflow.svg @@ -55,4 +55,4 @@     goarch: -goreleaser-full.yml +goreleaser-full.yml diff --git a/test/golden/svg/padding.svg b/test/golden/svg/padding.svg index aa0e346..4814773 100644 --- a/test/golden/svg/padding.svg +++ b/test/golden/svg/padding.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. -artichoke.hs +artichoke.hs diff --git a/test/golden/svg/shadow.svg b/test/golden/svg/shadow.svg index 87d1179..419a4d2 100644 --- a/test/golden/svg/shadow.svg +++ b/test/golden/svg/shadow.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. -artichoke.hs +artichoke.hs diff --git a/test/golden/svg/title.svg b/test/golden/svg/title.svg index 450ead4..53c35ac 100644 --- a/test/golden/svg/title.svg +++ b/test/golden/svg/title.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. -artichoke.hs +My artichoke code diff --git a/test/golden/svg/window.svg b/test/golden/svg/window.svg index 450ead4..520c421 100644 --- a/test/golden/svg/window.svg +++ b/test/golden/svg/window.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. -artichoke.hs +artichoke.hs From 0c51a1c1f96ad7753253a8b0a523206e864e2292 Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Mon, 10 Jun 2024 21:53:09 +0200 Subject: [PATCH 12/25] docs(README): better demo and better warning --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index be6e2db..bba0100 100644 --- a/README.md +++ b/README.md @@ -226,14 +226,14 @@ Display a custom title if `--window.title` is passed in the arguments (`--window Don't display the title if `--window.title` is passed in the arguments as empty string (`--window.title=""`). ```bash -freeze artichoke.hs --window +freeze artichoke.hs --window --window.title "My artichoke code" ``` output of freeze command, Haskell code block with window title applied > [!WARNING] > -> `--window.title` is not supported when using `--window=false`. +> The **title** can only be supported when using **window** mode (`--window=true`). ### Background From c087cce9510a39b61efe912ef7e59a2b72667848 Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Mon, 10 Jun 2024 21:53:43 +0200 Subject: [PATCH 13/25] test(freeze): using `t.Cleanup` and checking for child elements --- freeze_test.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/freeze_test.go b/freeze_test.go index bdfb985..da95ed7 100644 --- a/freeze_test.go +++ b/freeze_test.go @@ -107,7 +107,7 @@ func TestFreezeErrorFileMissing(t *testing.T) { func TestFreezeWindowTitleFilename(t *testing.T) { output := "artichoke-default-title.svg" - defer os.Remove(output) + t.Cleanup(func() { os.Remove(output) }) testTitle := "artichoke.hs" cmd := exec.Command(binary, "test/input/artichoke.hs", "--output", output, "--window") err := cmd.Run() @@ -122,6 +122,9 @@ func TestFreezeWindowTitleFilename(t *testing.T) { 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() @@ -132,7 +135,7 @@ func TestFreezeWindowTitleFilename(t *testing.T) { func TestFreezeCustomWindowTitle(t *testing.T) { output := "artichoke-custom-title.svg" - defer os.Remove(output) + t.Cleanup(func() { os.Remove(output) }) testTitle := "custom-test title" cmd := exec.Command(binary, "test/input/artichoke.hs", "--output", output, "--window.title", testTitle, "--window") err := cmd.Run() @@ -146,7 +149,11 @@ func TestFreezeCustomWindowTitle(t *testing.T) { if err != nil { t.Fatal("unexpected error", err) } - lastChild := doc.ChildElements()[len(doc.ChildElements())-1] + 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 { @@ -310,7 +317,7 @@ func TestFreezeConfigurations(t *testing.T) { }, { input: "test/input/artichoke.hs", - flags: []string{"--border.radius", "8", "--window", "--window.title", "auto"}, + flags: []string{"--border.radius", "8", "--window", "--window.title", "My artichoke code"}, output: "title", }, } From 8d2ab0a052293528d82070b31f6c9c1d70e9b093 Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Mon, 10 Jun 2024 21:54:29 +0200 Subject: [PATCH 14/25] feat(main): use `} else if {` --- main.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/main.go b/main.go index 7e65f34..8117c4f 100644 --- a/main.go +++ b/main.go @@ -304,11 +304,9 @@ func main() { } image.AddChild(title) } - } else { - if config.Title != "auto" { - err := errors.New("Title is not supported when not using a window controls") - printErrorFatal("Unable to add title", err) - } + } else if config.Title != "auto" { + err := errors.New("Title is not supported when not using a window controls") + printErrorFatal("Unable to add title", err) } if config.Border.Radius > 0 { From 014f87d9545db209ebe8217326ad6c525afa65a0 Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Tue, 11 Jun 2024 14:43:32 +0200 Subject: [PATCH 15/25] feat: added title position and title text --- config.go | 7 ++++++- configurations/full.json | 5 ++++- freeze_test.go | 4 ++-- interactive.go | 9 +++++++-- test/configurations/full.json | 5 ++++- 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/config.go b/config.go index 654c2da..211fe78 100644 --- a/config.go +++ b/config.go @@ -22,7 +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 string `json:"title,omitempty" help:"Display window title. {{--window.title=auto}} as default for input filename." prefix:"window." group:"Window" default:"auto"` + 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"` @@ -50,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"` +} + // Shadow is the configuration options for a drop shadow. type Shadow struct { Blur float64 `json:"blur" help:"Shadow Gaussian Blur." placeholder:"0"` diff --git a/configurations/full.json b/configurations/full.json index 561c51b..9ee527d 100644 --- a/configurations/full.json +++ b/configurations/full.json @@ -1,6 +1,9 @@ { "window": true, - "title": "auto", + "title": { + "text": "auto", + "position": "center" + }, "theme": "charm", "border": { "radius": 8, diff --git a/freeze_test.go b/freeze_test.go index da95ed7..3a3ee98 100644 --- a/freeze_test.go +++ b/freeze_test.go @@ -137,7 +137,7 @@ 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, "--window.title", testTitle, "--window") + cmd := exec.Command(binary, "test/input/artichoke.hs", "--output", output, "--title.text", testTitle, "--window") err := cmd.Run() if err != nil { @@ -317,7 +317,7 @@ func TestFreezeConfigurations(t *testing.T) { }, { input: "test/input/artichoke.hs", - flags: []string{"--border.radius", "8", "--window", "--window.title", "My artichoke code"}, + flags: []string{"--border.radius", "8", "--window", "--title.text", "My artichoke code"}, output: "title", }, } diff --git a/interactive.go b/interactive.go index b6ea4db..683b371 100644 --- a/interactive.go +++ b/interactive.go @@ -103,11 +103,16 @@ func runForm(config *Config) (*Config, error) { Inline(true). Value(&config.Window), - huh.NewInput().Title("Title"). + huh.NewInput().Title("Title text"). Placeholder("auto"). Inline(true). Prompt(""). - Value(&config.Title), + 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"), diff --git a/test/configurations/full.json b/test/configurations/full.json index 659aa62..4d0090c 100644 --- a/test/configurations/full.json +++ b/test/configurations/full.json @@ -1,6 +1,9 @@ { "window": true, - "title": "auto", + "title": { + "text": "auto", + "position": "center" + }, "theme": "charm", "border": { "radius": 8, From de16e849f623f5663434446743faee50f5649c18 Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Tue, 11 Jun 2024 14:44:19 +0200 Subject: [PATCH 16/25] feat: added title position logic --- main.go | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/main.go b/main.go index 8117c4f..7cbfa00 100644 --- a/main.go +++ b/main.go @@ -287,26 +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 != "" { - titleText := config.Title - if config.Title == "auto" { + if config.Title.Text != "" { + titleText := config.Title.Text + if config.Title.Text == "auto" { titleText = filepath.Base(config.Input) } - x := float64(config.Margin[left] + imageWidth/2) - y := float64(config.Margin[top] + config.Font.Size*float64(scale)) - title, err := svg.NewWindowTitle(x, y, scale, config.Font.Size, config.Font.Family, titleText, s) + 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} + 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) } image.AddChild(title) } - } else if config.Title != "auto" { + } 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" { + 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 { From 716540c467e82945fc6303f450544ec6931e1ce7 Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Tue, 11 Jun 2024 14:45:51 +0200 Subject: [PATCH 17/25] feat: added title positions Modified window controls to return the space that the elements occupy. --- svg/svg.go | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/svg/svg.go b/svg/svg.go index a75ac20..6b902ba 100644 --- a/svg/svg.go +++ b/svg/svg.go @@ -84,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") @@ -94,20 +94,42 @@ 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 + return bar, controlsWidth } -func NewWindowTitle(x, y, scale, fs float64, ff, text string, s *chroma.Style) (*etree.Element, error) { +// 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) { if text == "" || text == "-" { 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*float64(scale))) + 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", "middle") + input.CreateAttr("text-anchor", anchor) input.CreateAttr("alignment-baseline", "middle") - input.CreateAttr("dominant-baseline", "middle") input.SetText(text) Move(input, float64(x), float64(y)) return input, nil From 89fb93336bedbf225e7a672e05798944abdbd194 Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Tue, 11 Jun 2024 14:46:11 +0200 Subject: [PATCH 18/25] test(golden): `make golden` after changes --- test/golden/svg/artichoke-full.svg | 2 +- test/golden/svg/border-width.svg | 2 +- test/golden/svg/dimensions-config.svg | 2 +- test/golden/svg/eza.svg | 2 +- test/golden/svg/lines.svg | 2 +- test/golden/svg/margin.svg | 2 +- test/golden/svg/overflow-line-numbers.svg | 2 +- test/golden/svg/overflow.svg | 2 +- test/golden/svg/padding.svg | 2 +- test/golden/svg/shadow.svg | 2 +- test/golden/svg/title.svg | 2 +- test/golden/svg/window.svg | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/test/golden/svg/artichoke-full.svg b/test/golden/svg/artichoke-full.svg index 4551046..58d95cb 100644 --- a/test/golden/svg/artichoke-full.svg +++ b/test/golden/svg/artichoke-full.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. -artichoke.hs +artichoke.hs diff --git a/test/golden/svg/border-width.svg b/test/golden/svg/border-width.svg index dbc713f..96b1157 100644 --- a/test/golden/svg/border-width.svg +++ b/test/golden/svg/border-width.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. -artichoke.hs +artichoke.hs diff --git a/test/golden/svg/dimensions-config.svg b/test/golden/svg/dimensions-config.svg index 2e85d46..5018642 100644 --- a/test/golden/svg/dimensions-config.svg +++ b/test/golden/svg/dimensions-config.svg @@ -19,4 +19,4 @@ hello s = -artichoke.hs +artichoke.hs diff --git a/test/golden/svg/eza.svg b/test/golden/svg/eza.svg index b5db97f..0e7d14c 100644 --- a/test/golden/svg/eza.svg +++ b/test/golden/svg/eza.svg @@ -12,4 +12,4 @@ ansi.go cut_test.go go.mod main.go style.goconfig.go error.go go.sum Makefile svgconfig_test.go font help.go png.go tapesconfigurations font.go input pty.go testcut.go freeze_test.go interactive.go README.md -eza.ansi +eza.ansi diff --git a/test/golden/svg/lines.svg b/test/golden/svg/lines.svg index adcac25..9c686ee 100644 --- a/test/golden/svg/lines.svg +++ b/test/golden/svg/lines.svg @@ -16,4 +16,4 @@ 7 hello s = 8   "Hello, " ++ s ++ "." -artichoke.hs +artichoke.hs diff --git a/test/golden/svg/margin.svg b/test/golden/svg/margin.svg index ff91f62..bc1cf49 100644 --- a/test/golden/svg/margin.svg +++ b/test/golden/svg/margin.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. -artichoke.hs +artichoke.hs diff --git a/test/golden/svg/overflow-line-numbers.svg b/test/golden/svg/overflow-line-numbers.svg index e4b3387..38ba510 100644 --- a/test/golden/svg/overflow-line-numbers.svg +++ b/test/golden/svg/overflow-line-numbers.svg @@ -120,4 +120,4 @@ 108     secret_name: FURY_TOKEN -goreleaser-full.yml +goreleaser-full.yml diff --git a/test/golden/svg/overflow.svg b/test/golden/svg/overflow.svg index 2daaa12..ed79d78 100644 --- a/test/golden/svg/overflow.svg +++ b/test/golden/svg/overflow.svg @@ -55,4 +55,4 @@     goarch: -goreleaser-full.yml +goreleaser-full.yml diff --git a/test/golden/svg/padding.svg b/test/golden/svg/padding.svg index 4814773..bd87c92 100644 --- a/test/golden/svg/padding.svg +++ b/test/golden/svg/padding.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. -artichoke.hs +artichoke.hs diff --git a/test/golden/svg/shadow.svg b/test/golden/svg/shadow.svg index 419a4d2..15541fa 100644 --- a/test/golden/svg/shadow.svg +++ b/test/golden/svg/shadow.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. -artichoke.hs +artichoke.hs diff --git a/test/golden/svg/title.svg b/test/golden/svg/title.svg index 53c35ac..53b1aa7 100644 --- a/test/golden/svg/title.svg +++ b/test/golden/svg/title.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. -My artichoke code +My artichoke code diff --git a/test/golden/svg/window.svg b/test/golden/svg/window.svg index 520c421..1c85928 100644 --- a/test/golden/svg/window.svg +++ b/test/golden/svg/window.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. -artichoke.hs +artichoke.hs From 9341f160dc0de637783313a542d787dd360caa4f Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Tue, 11 Jun 2024 18:53:41 +0200 Subject: [PATCH 19/25] refactor(title): moved from `svg.go` to `main.go` - [x] Created struct for the positions of the title. - [x] Extracted into validator function for the title and position. - [x] Extracted position computing into `getPositions`. - [x] Simplify `NewWindowTitle` arguments --- main.go | 86 +++++++++++++++++++++++++++++++++++++++++++++--------- svg/svg.go | 44 ++-------------------------- 2 files changed, 74 insertions(+), 56 deletions(-) diff --git a/main.go b/main.go index 7cbfa00..9213fdb 100644 --- a/main.go +++ b/main.go @@ -289,32 +289,26 @@ func main() { if config.Window { x := 19.0 * scale y := 12.0 * scale - windowControls, controlsWidth := svg.NewWindowControls(5.5*float64(scale), x, y) + windowControls := 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) + windowChilds := windowControls.ChildElements() + if len(windowChilds) == 0 { + printErrorFatal("Unable to add title", errors.New("no window controls found")) } - 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} - title, err := svg.NewWindowTitle(titlePos, config.Title.Position, config.Font.Size*float64(scale), config.Font.Family, titleText, s) + controlsWidth := float64(len(windowChilds)) * float64(x) + titlePos := getPositions(config, x, y, imageWidth, controlsWidth) + title, err := NewWindowTitle(config, titlePos, scale, s) if err != nil { printErrorFatal("Unable to add title", err) } image.AddChild(title) } - } else if config.Title.Text != "auto" { + } else if config.Title.Text != "auto" || config.Title.Position != "center" { 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" { - 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 { @@ -479,3 +473,67 @@ var outputHeader = lipgloss.NewStyle().Foreground(lipgloss.Color("#F1F1F1")).Bac func printFilenameOutput(filename string) { fmt.Println(lipgloss.JoinHorizontal(lipgloss.Center, outputHeader.String(), filename)) } + +type Positions struct { + Left float64 + Center float64 + Right float64 + Top float64 +} + +func getPositions(config Config, x, y, imgW, controlsWidth float64) Positions { + return Positions{ + Left: config.Margin[left] + x + controlsWidth, + Center: imgW / 2, + Right: imgW - (config.Margin[right] + x), + Top: config.Margin[top] + y, + } +} + +func (title Title) Validate(value string) error { + if title.Text == "" || title.Text == "-" { + return errors.New("Invalid title provided") + } + if title.Position != "left" && title.Position != "center" && title.Position != "right" { + return errors.New("Invalid title position. Must be one of \"left\", \"center\", or \"right\"") + } + return nil +} + +// NewWindowTitle returns a title element with the given text. +func NewWindowTitle(config Config, positions Positions, scale float64, s *chroma.Style) (*etree.Element, error) { + titleText := config.Title.Text + err := config.Title.Validate(titleText) + if err != nil { + return nil, err + } + if titleText == "auto" { + titleText = filepath.Base(config.Input) + } + x := 0.0 + y := positions.Top + var anchor string + switch config.Title.Position { + case "left": + x = positions.Left + anchor = "start" + break + case "center": + x = positions.Center + anchor = "middle" + break + case "right": + x = positions.Right + anchor = "end" + break + } + input := etree.NewElement("text") + input.CreateAttr("font-size", fmt.Sprintf("%.2fpx", config.Font.Size*float64(scale))) + input.CreateAttr("fill", s.Get(chroma.Text).Colour.String()) + input.CreateAttr("font-family", config.Font.Family) + input.CreateAttr("text-anchor", anchor) + input.CreateAttr("alignment-baseline", "middle") + input.SetText(titleText) + svg.Move(input, float64(x), float64(y)) + return input, err +} diff --git a/svg/svg.go b/svg/svg.go index 6b902ba..a12f9cb 100644 --- a/svg/svg.go +++ b/svg/svg.go @@ -1,12 +1,10 @@ package svg import ( - "errors" "fmt" "strconv" "strings" - "github.com/alecthomas/chroma/v2" "github.com/beevik/etree" ) @@ -84,7 +82,7 @@ const ( ) // NewWindowControls returns a colorful window bar element. -func NewWindowControls(r float64, x, y float64) (*etree.Element, float64) { +func NewWindowControls(r float64, x, y float64) *etree.Element { bar := etree.NewElement("svg") for i, color := range []string{red, yellow, green} { circle := etree.NewElement("circle") @@ -94,45 +92,7 @@ func NewWindowControls(r float64, x, y float64) (*etree.Element, float64) { circle.CreateAttr("fill", color) bar.AddChild(circle) } - controlsWidth := float64(len(bar.ChildElements()))*float64(x) + float64(r)*2 - 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) { - if text == "" || text == "-" { - 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 + return bar } // SetDimensions sets the width and height of the given element. From af731cf5585357bcba3ea9e836bd6e311edc63df Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Tue, 11 Jun 2024 18:58:13 +0200 Subject: [PATCH 20/25] docs: updated `--title` usage --- README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index bba0100..2111ac9 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,8 @@ 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. +- [`--title.text`](#window-title): Display input file or custom text when window controls are displayed. +- [`--title.position`](#window-title): Position of the title text. - [`--border.width`](#border-width): Border width thickness. - [`--border.color`](#border-width): Border color. - [`--shadow.blur`](#shadow): Shadow Gaussian Blur. @@ -219,14 +220,16 @@ freeze artichoke.hs --window #### 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 the input file as the title of the window if `--title.text` is not passed in the arguments (`--title.text=auto` as default). -Display a custom title if `--window.title` is passed in the arguments (`--window.title="custom title"`). +Display a custom title if `--title.text` is passed in the arguments (`--title.text="custom title"`). -Don't display the title if `--window.title` is passed in the arguments as empty string (`--window.title=""`). +Don't display the title if `--title.text` is passed in the arguments as empty string (`--title.text=""`). + +To position the title text, use `--title.position` with `left`, `center` or `right` (`--title.position=center` as default). ```bash -freeze artichoke.hs --window --window.title "My artichoke code" +freeze artichoke.hs --window --title.text "My artichoke code" ``` output of freeze command, Haskell code block with window title applied From a2ba0f3c3bab79f780be3991eb82a7d965e79f4a Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Tue, 11 Jun 2024 19:01:07 +0200 Subject: [PATCH 21/25] fix: removed `group:"Window"` from `Title` --- config.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.go b/config.go index 211fe78..bb1434c 100644 --- a/config.go +++ b/config.go @@ -51,8 +51,8 @@ type Config struct { } 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"` + Text string `json:"title" help:"Display window title. {{--title.text=auto}} as default for input filename." default:"auto"` + Position string `json:"position" help:"Position of window title, one of {{left}}, {{center}}, or {{right}}. {{--title.position=center}} as default." default:"center"` } // Shadow is the configuration options for a drop shadow. From 406de9261267095a748a911e103038b50ff5b003 Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Wed, 12 Jun 2024 10:46:08 +0200 Subject: [PATCH 22/25] refactor: switch and value usage --- main.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/main.go b/main.go index 9213fdb..dfb388c 100644 --- a/main.go +++ b/main.go @@ -491,13 +491,15 @@ func getPositions(config Config, x, y, imgW, controlsWidth float64) Positions { } func (title Title) Validate(value string) error { - if title.Text == "" || title.Text == "-" { - return errors.New("Invalid title provided") + if value == "" || value == "-" { + return errors.New("Invalid title text provided.") } - if title.Position != "left" && title.Position != "center" && title.Position != "right" { - return errors.New("Invalid title position. Must be one of \"left\", \"center\", or \"right\"") + switch title.Position { + case "left", "center", "right": + return nil + default: + return errors.New("Invalid title position. Must be one of \"left\", \"center\", or \"right\".") } - return nil } // NewWindowTitle returns a title element with the given text. From 11b73ac5e105e2ab30572cc776cdd36cd10dd2c8 Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Wed, 12 Jun 2024 11:32:46 +0200 Subject: [PATCH 23/25] refactor: use constants for positions --- main.go | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/main.go b/main.go index dfb388c..e203ff8 100644 --- a/main.go +++ b/main.go @@ -490,12 +490,18 @@ func getPositions(config Config, x, y, imgW, controlsWidth float64) Positions { } } -func (title Title) Validate(value string) error { - if value == "" || value == "-" { +const ( + posLeft = "left" + posCenter = "center" + posRight = "right" +) + +func (title Title) Validate() error { + if title.Text == "" || title.Text == "-" { return errors.New("Invalid title text provided.") } switch title.Position { - case "left", "center", "right": + case posLeft, posCenter, posRight: return nil default: return errors.New("Invalid title position. Must be one of \"left\", \"center\", or \"right\".") @@ -504,11 +510,11 @@ func (title Title) Validate(value string) error { // NewWindowTitle returns a title element with the given text. func NewWindowTitle(config Config, positions Positions, scale float64, s *chroma.Style) (*etree.Element, error) { - titleText := config.Title.Text - err := config.Title.Validate(titleText) + err := config.Title.Validate() if err != nil { return nil, err } + titleText := config.Title.Text if titleText == "auto" { titleText = filepath.Base(config.Input) } @@ -516,15 +522,15 @@ func NewWindowTitle(config Config, positions Positions, scale float64, s *chroma y := positions.Top var anchor string switch config.Title.Position { - case "left": + case posLeft: x = positions.Left anchor = "start" break - case "center": + case posCenter: x = positions.Center anchor = "middle" break - case "right": + case posRight: x = positions.Right anchor = "end" break From 7a46616fe207f81d87bf3d14fc9396e6a73eb9a1 Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Wed, 12 Jun 2024 17:18:59 +0200 Subject: [PATCH 24/25] feat: increase font size a bit and improved center with controls fix: fixed height problem when using `librsvg` --- main.go | 13 +++++++++---- png.go | 9 ++++++++- test/golden/svg/artichoke-full.svg | 2 +- test/golden/svg/border-width.svg | 2 +- test/golden/svg/dimensions-config.svg | 2 +- test/golden/svg/eza.svg | 2 +- test/golden/svg/lines.svg | 2 +- test/golden/svg/margin.svg | 2 +- test/golden/svg/overflow-line-numbers.svg | 2 +- test/golden/svg/overflow.svg | 2 +- test/golden/svg/padding.svg | 2 +- test/golden/svg/shadow.svg | 2 +- test/golden/svg/title.svg | 2 +- test/golden/svg/window.svg | 2 +- 14 files changed, 29 insertions(+), 17 deletions(-) diff --git a/main.go b/main.go index e203ff8..0892955 100644 --- a/main.go +++ b/main.go @@ -289,7 +289,8 @@ func main() { if config.Window { x := 19.0 * scale y := 12.0 * scale - windowControls := svg.NewWindowControls(5.5*float64(scale), x, y) + r := 5.5 * scale + windowControls := svg.NewWindowControls(r, x, y) svg.Move(windowControls, float64(config.Margin[left]), float64(config.Margin[top])) image.AddChild(windowControls) config.Padding[top] += (15 * scale) @@ -300,7 +301,7 @@ func main() { } controlsWidth := float64(len(windowChilds)) * float64(x) titlePos := getPositions(config, x, y, imageWidth, controlsWidth) - title, err := NewWindowTitle(config, titlePos, scale, s) + title, err := NewWindowTitle(config, titlePos, scale, s, r) if err != nil { printErrorFatal("Unable to add title", err) } @@ -509,7 +510,7 @@ func (title Title) Validate() error { } // NewWindowTitle returns a title element with the given text. -func NewWindowTitle(config Config, positions Positions, scale float64, s *chroma.Style) (*etree.Element, error) { +func NewWindowTitle(config Config, positions Positions, scale float64, s *chroma.Style, fs float64) (*etree.Element, error) { err := config.Title.Validate() if err != nil { return nil, err @@ -520,6 +521,10 @@ func NewWindowTitle(config Config, positions Positions, scale float64, s *chroma } x := 0.0 y := positions.Top + moveY := hasLibsvg() + if moveY == nil { + y += fs + } var anchor string switch config.Title.Position { case posLeft: @@ -536,7 +541,7 @@ func NewWindowTitle(config Config, positions Positions, scale float64, s *chroma break } input := etree.NewElement("text") - input.CreateAttr("font-size", fmt.Sprintf("%.2fpx", config.Font.Size*float64(scale))) + input.CreateAttr("font-size", fmt.Sprintf("%.2fpx", fs*float64(scale)-config.Font.Size)) input.CreateAttr("fill", s.Get(chroma.Text).Colour.String()) input.CreateAttr("font-family", config.Font.Family) input.CreateAttr("text-anchor", anchor) diff --git a/png.go b/png.go index af0348f..2a54481 100644 --- a/png.go +++ b/png.go @@ -11,12 +11,19 @@ import ( "github.com/kanrichan/resvg-go" ) -func libsvgConvert(doc *etree.Document, w, h float64, output string) error { +func hasLibsvg() error { _, err := exec.LookPath("rsvg-convert") if err != nil { return err } + return err +} +func libsvgConvert(doc *etree.Document, w, h float64, output string) error { + err := hasLibsvg() + if err != nil { + return err + } svg, err := doc.WriteToBytes() if err != nil { return err diff --git a/test/golden/svg/artichoke-full.svg b/test/golden/svg/artichoke-full.svg index 58d95cb..7f24cc6 100644 --- a/test/golden/svg/artichoke-full.svg +++ b/test/golden/svg/artichoke-full.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. -artichoke.hs +artichoke.hs diff --git a/test/golden/svg/border-width.svg b/test/golden/svg/border-width.svg index 96b1157..ce36fae 100644 --- a/test/golden/svg/border-width.svg +++ b/test/golden/svg/border-width.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. -artichoke.hs +artichoke.hs diff --git a/test/golden/svg/dimensions-config.svg b/test/golden/svg/dimensions-config.svg index 5018642..62e6661 100644 --- a/test/golden/svg/dimensions-config.svg +++ b/test/golden/svg/dimensions-config.svg @@ -19,4 +19,4 @@ hello s = -artichoke.hs +artichoke.hs diff --git a/test/golden/svg/eza.svg b/test/golden/svg/eza.svg index 0e7d14c..866e6ec 100644 --- a/test/golden/svg/eza.svg +++ b/test/golden/svg/eza.svg @@ -12,4 +12,4 @@ ansi.go cut_test.go go.mod main.go style.goconfig.go error.go go.sum Makefile svgconfig_test.go font help.go png.go tapesconfigurations font.go input pty.go testcut.go freeze_test.go interactive.go README.md -eza.ansi +eza.ansi diff --git a/test/golden/svg/lines.svg b/test/golden/svg/lines.svg index 9c686ee..864cfe8 100644 --- a/test/golden/svg/lines.svg +++ b/test/golden/svg/lines.svg @@ -16,4 +16,4 @@ 7 hello s = 8   "Hello, " ++ s ++ "." -artichoke.hs +artichoke.hs diff --git a/test/golden/svg/margin.svg b/test/golden/svg/margin.svg index bc1cf49..10c3926 100644 --- a/test/golden/svg/margin.svg +++ b/test/golden/svg/margin.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. -artichoke.hs +artichoke.hs diff --git a/test/golden/svg/overflow-line-numbers.svg b/test/golden/svg/overflow-line-numbers.svg index 38ba510..5e51ced 100644 --- a/test/golden/svg/overflow-line-numbers.svg +++ b/test/golden/svg/overflow-line-numbers.svg @@ -120,4 +120,4 @@ 108     secret_name: FURY_TOKEN -goreleaser-full.yml +goreleaser-full.yml diff --git a/test/golden/svg/overflow.svg b/test/golden/svg/overflow.svg index ed79d78..2bccb45 100644 --- a/test/golden/svg/overflow.svg +++ b/test/golden/svg/overflow.svg @@ -55,4 +55,4 @@     goarch: -goreleaser-full.yml +goreleaser-full.yml diff --git a/test/golden/svg/padding.svg b/test/golden/svg/padding.svg index bd87c92..5cfe326 100644 --- a/test/golden/svg/padding.svg +++ b/test/golden/svg/padding.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. -artichoke.hs +artichoke.hs diff --git a/test/golden/svg/shadow.svg b/test/golden/svg/shadow.svg index 15541fa..da980bc 100644 --- a/test/golden/svg/shadow.svg +++ b/test/golden/svg/shadow.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. -artichoke.hs +artichoke.hs diff --git a/test/golden/svg/title.svg b/test/golden/svg/title.svg index 53b1aa7..080690a 100644 --- a/test/golden/svg/title.svg +++ b/test/golden/svg/title.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. -My artichoke code +My artichoke code diff --git a/test/golden/svg/window.svg b/test/golden/svg/window.svg index 1c85928..5547689 100644 --- a/test/golden/svg/window.svg +++ b/test/golden/svg/window.svg @@ -26,4 +26,4 @@ -- Alcachofa, if you were wondering, is artichoke in Spanish. -artichoke.hs +artichoke.hs From bb40c9ba02db2deb57fefe91785e457665f4ccfe Mon Sep 17 00:00:00 2001 From: AlejandroSuero Date: Wed, 12 Jun 2024 22:42:07 +0200 Subject: [PATCH 25/25] fix: simply return err --- png.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/png.go b/png.go index 2a54481..a3069fc 100644 --- a/png.go +++ b/png.go @@ -13,9 +13,6 @@ import ( func hasLibsvg() error { _, err := exec.LookPath("rsvg-convert") - if err != nil { - return err - } return err }