├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── example
└── main.go
├── giohyperlink.go
├── giohyperlink_android.go
├── giohyperlink_android.jar
├── giohyperlink_android.java
├── giohyperlink_darwin.go
├── giohyperlink_ios.go
├── giohyperlink_js.go
├── giohyperlink_unix.go
├── giohyperlink_windows.go
├── go.mod
└── go.sum
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | .idea
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This project is dual-licensed under the UNLICENSE or
2 | the MIT license.
3 |
4 | SPDX-License-Identifier: Unlicense OR MIT
5 |
6 | You may use the project under the terms of either license.
7 |
8 | ----
9 | The MIT License (MIT)
10 |
11 | Copyright (c) 2020 Inkeliz
12 |
13 | Permission is hereby granted, free of charge, to any person obtaining a copy
14 | of this software and associated documentation files (the "Software"), to deal
15 | in the Software without restriction, including without limitation the rights
16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | copies of the Software, and to permit persons to whom the Software is
18 | furnished to do so, subject to the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be included in
21 | all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 | THE SOFTWARE.
30 | ---
31 |
32 | ---
33 | The UNLICENSE
34 |
35 | This is free and unencumbered software released into the public domain.
36 |
37 | Anyone is free to copy, modify, publish, use, compile, sell, or
38 | distribute this software, either in source code form or as a compiled
39 | binary, for any purpose, commercial or non-commercial, and by any
40 | means.
41 |
42 | In jurisdictions that recognize copyright laws, the author or authors
43 | of this software dedicate any and all copyright interest in the
44 | software to the public domain. We make this dedication for the benefit
45 | of the public at large and to the detriment of our heirs and
46 | successors. We intend this dedication to be an overt act of
47 | relinquishment in perpetuity of all present and future rights to this
48 | software under copyright law.
49 |
50 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
51 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
52 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
53 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
54 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
55 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
56 | OTHER DEALINGS IN THE SOFTWARE.
57 |
58 | For more information, please refer to
59 | ---
60 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | GioHyperlink
2 | --------
3 |
4 | Opens a hyperlink in the default browser. 🤩
5 |
6 | ## Setup
7 |
8 | First, you need to `go get github.com/inkeliz/giohyperlink`, then you need to provide `giohyperlink` access to the Window events, so you need to add the following to your main loop function:
9 |
10 | ```rust
11 |
12 | ```diff
13 | for evt := range w.Events() { // Gio main event loop
14 | + giohyperlink.ListenEvents(e)
15 |
16 | switch evt := evt.(type) {
17 | // ...
18 | }
19 | }
20 | ```
21 |
22 | > _⚠️In some OSes (Windows, macOS...) this setup is optional, but it's recommended to do it anyway._
23 |
24 | ## Usage
25 |
26 | To open one link, you can use the `Open` function:
27 |
28 | ```go
29 | giohyperlink.Open("https://github.com")
30 | ```
31 |
32 | That will open the link in the default browser. You can use `OpenURL` to open a `*url.URL`:
33 |
34 | ```go
35 | giohyperlink.OpenURL(&url.URL{
36 | Scheme: "https",
37 | Host: "github.com",
38 | })
39 | ```
40 |
41 | By default only HTTP and HTTPS links are allowed, but you can change that by changing `InsecureIgnoreScheme` to `true`,
42 | you should validate the URL and scheme on your own.
43 |
--------------------------------------------------------------------------------
/example/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "gioui.org/app"
5 | "gioui.org/f32"
6 | "gioui.org/font/gofont"
7 | "gioui.org/io/system"
8 | "gioui.org/layout"
9 | "gioui.org/op"
10 | "gioui.org/op/clip"
11 | "gioui.org/op/paint"
12 | "gioui.org/text"
13 | "gioui.org/unit"
14 | "gioui.org/widget"
15 | "gioui.org/widget/material"
16 | "github.com/inkeliz/giohyperlink"
17 | "image/color"
18 | "log"
19 | "os"
20 | "strings"
21 | )
22 |
23 | func main() {
24 | go func() {
25 | w := app.NewWindow(app.Size(unit.Dp(800), unit.Dp(700)), app.MinSize(unit.Dp(400), unit.Dp(400)))
26 | if err := loop(w); err != nil {
27 | panic(err)
28 | }
29 | os.Exit(0)
30 | }()
31 |
32 | app.Main()
33 | }
34 |
35 | func loop(w *app.Window) error {
36 | defer w.Close()
37 | var ops op.Ops
38 | for {
39 | select {
40 | case e := <-w.Events():
41 |
42 | // You need to include ListenEvents()
43 | giohyperlink.ListenEvents(e)
44 | //////////////////////////////////////
45 |
46 | switch e := e.(type) {
47 | case system.DestroyEvent:
48 | return e.Err
49 | case system.FrameEvent:
50 | gtx := layout.NewContext(&ops, e)
51 |
52 | for _, ee := range InputAction.Events() {
53 | if _, ok := ee.(widget.SubmitEvent); !ok {
54 | continue
55 | }
56 |
57 | if err := giohyperlink.Open(InputAction.Text()); err != nil {
58 | log.Println(err)
59 | }
60 | }
61 |
62 | if ButtonAction.Clicked() {
63 | if err := giohyperlink.Open(InputAction.Text()); err != nil {
64 | log.Println(err)
65 | }
66 | }
67 |
68 | render(gtx)
69 | e.Frame(gtx.Ops)
70 | }
71 | }
72 | }
73 | }
74 |
75 | func render(gtx layout.Context) layout.Dimensions {
76 | return layout.Flex{Axis: layout.Vertical, Spacing: layout.SpaceSides}.Layout(gtx,
77 |
78 | layout.Rigid(func(gtx layout.Context) layout.Dimensions {
79 | return MarginDesign.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
80 | return InputBackgroundDesign.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
81 | return InputDesign.Layout(gtx, InputAction, "Type some webite (e.g https://gioui.org)", "https://gioui.org")
82 | })
83 | })
84 | }),
85 |
86 | layout.Rigid(func(gtx layout.Context) layout.Dimensions {
87 |
88 | return MarginDesign.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
89 | return ButtonDesign.Layout(gtx, ButtonAction, "OPEN")
90 | })
91 | }),
92 |
93 | )
94 | }
95 |
96 | // Actions
97 | var (
98 | ButtonAction = &widget.Clickable{}
99 | InputAction = &widget.Editor{SingleLine: true, Submit: true}
100 | )
101 |
102 | // Design
103 | var (
104 | ButtonDesign = &Button{Color: color.NRGBA{R: 255, G: 255, B: 255, A: 255}, TextSize: unit.Sp(16).Scale(14.0 / 16.0), Background: color.NRGBA{R: 135, G: 156, B: 251, A: 255}, BorderRadius: unit.Dp(4), Modifier: strings.ToUpper, Inset: layout.Inset{Top: unit.Dp(10), Right: unit.Dp(12), Bottom: unit.Dp(10), Left: unit.Dp(12)}}
105 | InputDesign = &Input{Font: text.Font{}, TextSize: unit.Dp(14), Color: color.NRGBA{R: 100, G: 130, B: 60, A: 255}, HintColor: color.NRGBA{R: 120, G: 120, B: 120, A: 255}}
106 | InputBackgroundDesign = &Background{Color: color.NRGBA{R: 234, G: 236, B: 231, A: 255}, Inset: layout.UniformInset(unit.Dp(13)), BorderRadius: unit.Dp(10)}
107 |
108 | MarginDesign = layout.Inset{Right: unit.Dp(30), Bottom: unit.Dp(6), Left: unit.Dp(30), Top: unit.Dp(6)}
109 | )
110 |
111 | var defaultMaterial = material.NewTheme(gofont.Collection())
112 |
113 | type Input struct {
114 | Font text.Font
115 | TextSize unit.Value
116 | Color color.NRGBA
117 | HintColor color.NRGBA
118 | }
119 |
120 | var alreadySetEditor = make(map[*widget.Editor]bool)
121 |
122 | func (i *Input) Layout(gtx layout.Context, editor *widget.Editor, hint string, value string) layout.Dimensions {
123 | e := material.Editor(defaultMaterial, editor, hint)
124 | e.TextSize = i.TextSize
125 | e.Color = i.Color
126 | e.Hint = hint
127 | e.HintColor = i.HintColor
128 |
129 | if value != "" {
130 | if _, ok := alreadySetEditor[editor]; !ok {
131 | editor.SetText(value)
132 | editor.MoveCaret(editor.Len(), editor.Len())
133 | alreadySetEditor[editor] = true
134 | }
135 | }
136 |
137 | return e.Layout(gtx)
138 | }
139 |
140 | type Button struct {
141 | Color color.NRGBA
142 | Font text.Font
143 | TextSize unit.Value
144 | Background color.NRGBA
145 | BorderRadius unit.Value
146 | Modifier func(string) string
147 | Inset layout.Inset
148 | }
149 |
150 | func (b *Button) Layout(gtx layout.Context, clickable *widget.Clickable, s string) layout.Dimensions {
151 | style := material.Button(defaultMaterial, clickable, s)
152 | style.Color = b.Color
153 | style.Font = b.Font
154 | style.TextSize = b.TextSize
155 | style.Background = b.Background
156 | style.CornerRadius = b.BorderRadius
157 | style.Inset = b.Inset
158 |
159 | if b.Modifier != nil {
160 | style.Text = b.Modifier(s)
161 | }
162 |
163 | return style.Layout(gtx)
164 | }
165 |
166 | type Background struct {
167 | Color color.NRGBA
168 | BorderRadius unit.Value
169 | Inset layout.Inset
170 | }
171 |
172 | func (b *Background) Layout(gtx layout.Context, w layout.Widget) layout.Dimensions {
173 |
174 | macro := op.Record(gtx.Ops)
175 | dimensions := b.Inset.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
176 | return w(gtx)
177 | })
178 | saved := macro.Stop()
179 |
180 | return layout.Stack{}.Layout(gtx,
181 | layout.Stacked(func(gtx layout.Context) layout.Dimensions {
182 | background := f32.Rectangle{Max: f32.Point{X: float32(dimensions.Size.X), Y: float32(dimensions.Size.Y)}}
183 |
184 | rr := float32(gtx.Px(b.BorderRadius))
185 | stack := clip.RRect{Rect: background, NE: rr, NW: rr, SE: rr, SW: rr}.Op(gtx.Ops).Push(gtx.Ops)
186 | paint.Fill(gtx.Ops, b.Color)
187 | stack.Pop()
188 |
189 | return dimensions
190 | }),
191 |
192 | layout.Expanded(func(gtx layout.Context) layout.Dimensions {
193 | saved.Add(gtx.Ops)
194 | return dimensions
195 | }),
196 | )
197 | }
198 |
--------------------------------------------------------------------------------
/giohyperlink.go:
--------------------------------------------------------------------------------
1 | package giohyperlink
2 |
3 | import (
4 | "errors"
5 | "net/url"
6 |
7 | "gioui.org/io/event"
8 | )
9 |
10 | var (
11 | // ErrNotReady may occur when try to open a URL before the initialization is done.
12 | ErrNotReady = errors.New("some needed library was not loaded yet, make use that you are using ListenEvents()")
13 | // ErrInvalidURL occur when provide an invalid URL, like a non http/https URL.
14 | ErrInvalidURL = errors.New("given url is invalid")
15 | )
16 |
17 | var (
18 | // InsecureIgnoreScheme will remove any attempt to validate the URL
19 | // It's "false" by default. Set it to "true" if you are using a custom scheme (like "myapp://").
20 | InsecureIgnoreScheme bool
21 | )
22 |
23 | // ListenEvents must get all the events from Gio, in order to get the GioView once it's ready. You need
24 | // to include that function where you listen for Gio events.
25 | //
26 | // Similar as:
27 | //
28 | // select {
29 | // case e := <-w.Events():
30 | // giohyperlink.ListenEvents(e)
31 | //
32 | // switch e := e.(type) {
33 | // (( ... your code ... ))
34 | func ListenEvents(event event.Event) {
35 | listenEvents(event)
36 | }
37 |
38 | // OpenURL opens the given url.URL in the browser (or equivalent app)
39 | func OpenURL(u *url.URL) error {
40 | if u == nil || u.Scheme == "" || ((u.Scheme != "http" && u.Scheme != "https") && InsecureIgnoreScheme == false) {
41 | return ErrInvalidURL
42 | }
43 |
44 | return open(u)
45 | }
46 |
47 | // Open opens the given string url in the browser (or equivalent app).
48 | func Open(uri string) error {
49 | if uri == "" {
50 | return ErrInvalidURL
51 | }
52 |
53 | u, err := url.Parse(uri)
54 | if err != nil {
55 | return ErrInvalidURL
56 | }
57 |
58 | return OpenURL(u)
59 | }
60 |
--------------------------------------------------------------------------------
/giohyperlink_android.go:
--------------------------------------------------------------------------------
1 | // +build android
2 |
3 | package giohyperlink
4 |
5 | import (
6 | "gioui.org/app"
7 | "gioui.org/io/event"
8 | "git.wow.st/gmp/jni"
9 | "net/url"
10 | )
11 |
12 | //go:generate javac -source 8 -target 8 -bootclasspath $ANDROID_HOME\platforms\android-29\android.jar -d $TEMP\giohyperlink\classes giohyperlink_android.java
13 | //go:generate jar cf giohyperlink_android.jar -C $TEMP\giohyperlink\classes .
14 |
15 | var view uintptr
16 |
17 | func listenEvents(event event.Event) {
18 | if e, ok := event.(app.ViewEvent); ok {
19 | view = e.View
20 | }
21 | }
22 |
23 | func open(u *url.URL) error {
24 | if view == 0 {
25 | return ErrNotReady
26 | }
27 |
28 | return jni.Do(jni.JVMFor(app.JavaVM()), func(env jni.Env) error {
29 |
30 | // Get the GioView object
31 | obj := jni.Object(view)
32 | cls := jni.GetObjectClass(env, obj)
33 |
34 | // Run getClass() to get the Class of GioView
35 | mid := jni.GetMethodID(env, cls, "getClass", "()Ljava/lang/Class;")
36 | obj, err := jni.CallObjectMethod(env, obj, mid)
37 | if err != nil {
38 | panic(err)
39 | }
40 |
41 | // Run getClassLoader() to get the ClassLoader from Class
42 | cls = jni.GetObjectClass(env, obj)
43 | mid = jni.GetMethodID(env, cls, "getClassLoader", "()Ljava/lang/ClassLoader;")
44 | obj, err = jni.CallObjectMethod(env, obj, mid)
45 | if err != nil {
46 | panic(err)
47 | }
48 |
49 | // Run findClass() from ClassLoader. The return is our custom class (in that case it's the
50 | // com.inkeliz.giohyperlink.giohyperlink_android, that name is defined on `giohyperlink_android.java`.
51 | cls = jni.GetObjectClass(env, obj)
52 | mid = jni.GetMethodID(env, cls, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;")
53 | clso, err := jni.CallObjectMethod(env, obj, mid, jni.Value(jni.JavaString(env, `com.inkeliz.giohyperlink.giohyperlink_android`)))
54 | if err != nil {
55 | panic(err)
56 | }
57 |
58 | // We need to convert Object (because we use CallObjectMethod) to jni.Class type
59 | cls = jni.Class(clso)
60 |
61 | // Create a new Object from our class. It's almost the same of `new giohyperlink_android()`
62 | // The `` and `NewObject` are used to create a "variable" with the class that we get before.
63 | mid = jni.GetMethodID(env, cls, "", `()V`)
64 | obj, err = jni.NewObject(env, cls, mid)
65 | if err != nil {
66 | panic(err)
67 | }
68 |
69 | // Run the `open()` function from our custom Java. That is defined inside the `giohyperlink_android` class
70 | // you can view that at giohyperlink_android.java.
71 | //
72 | // Our java function is:
73 | // public void open(View view, String url) {}
74 | //
75 | // So we need to supply the view argument and the url argument. That view argument is the `GioView` itself
76 | // the GioView is the `view` variable, which we got from app.ViewEvents.
77 | mid = jni.GetMethodID(env, cls, "open", "(Landroid/view/View;Ljava/lang/String;)V")
78 | err = jni.CallVoidMethod(env, obj, mid, jni.Value(view), jni.Value(jni.JavaString(env, u.String())))
79 | if err != nil {
80 | panic(err)
81 | }
82 |
83 | return nil
84 | })
85 | }
86 |
--------------------------------------------------------------------------------
/giohyperlink_android.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inkeliz/giohyperlink/2ac5d54abdce8544be0cd008e9ee343b930e44b0/giohyperlink_android.jar
--------------------------------------------------------------------------------
/giohyperlink_android.java:
--------------------------------------------------------------------------------
1 | package com.inkeliz.giohyperlink_android;
2 |
3 | import android.app.Activity;
4 | import android.view.View;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.net.Uri;
8 |
9 | public class giohyperlink_android {
10 |
11 | public void open(View view, String url) {
12 |
13 | // Create the Intent, which is to open the given URL
14 | Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
15 |
16 | // Get GioActivity from GioView
17 | Activity activity = (Activity)view.getContext();
18 |
19 | // Run on main thread, from GioActivity
20 | activity.runOnUiThread(new Runnable() {
21 | public void run() {
22 |
23 | // Create the activity from GioActivity
24 | activity.startActivity(intent);
25 | }
26 | });
27 |
28 | }
29 |
30 | }
--------------------------------------------------------------------------------
/giohyperlink_darwin.go:
--------------------------------------------------------------------------------
1 | // +build darwin,!ios
2 |
3 | package giohyperlink
4 |
5 | import (
6 | "gioui.org/io/event"
7 | "net/url"
8 | "os/exec"
9 | )
10 |
11 | func listenEvents(_ event.Event) {
12 | // NO-OP
13 | }
14 |
15 | func open(u *url.URL) error {
16 | return exec.Command("open", u.String()).Run()
17 | }
18 |
--------------------------------------------------------------------------------
/giohyperlink_ios.go:
--------------------------------------------------------------------------------
1 | //go:build ios
2 | // +build ios
3 |
4 | package giohyperlink
5 |
6 | /*
7 | #cgo CFLAGS: -Werror -xobjective-c -fmodules -fobjc-arc
8 |
9 | @import UIKit;
10 |
11 | void openLink(char *u) {
12 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString: @(u)] options:@{} completionHandler:nil];
13 | }
14 | */
15 | import "C"
16 |
17 | import (
18 | "gioui.org/io/event"
19 | "net/url"
20 | "unsafe"
21 | )
22 |
23 | func listenEvents(_ event.Event) {
24 | // NO-OP
25 | }
26 |
27 | func open(u *url.URL) error {
28 | u.RawQuery = u.Query().Encode()
29 | cURL := C.CString(u.String())
30 | C.openLink(cURL)
31 | C.free(unsafe.Pointer(cURL))
32 | return nil
33 | }
34 |
--------------------------------------------------------------------------------
/giohyperlink_js.go:
--------------------------------------------------------------------------------
1 | // +build js
2 |
3 | package giohyperlink
4 |
5 | import (
6 | "gioui.org/io/event"
7 | "gioui.org/io/system"
8 | "net/url"
9 | "syscall/js"
10 | )
11 |
12 | var (
13 | _document = js.Global().Get("document")
14 | _body = js.Global().Get("document").Get("body")
15 | )
16 |
17 | func listenEvents(event event.Event) {
18 | if _, ok := event.(system.StageEvent); ok {
19 | links := _body.Call("querySelectorAll", "a.giohyperlink")
20 | if !links.Truthy() {
21 | return
22 | }
23 | for i := 0; i < links.Length(); i++ {
24 | _body.Call("removeChild", links.Index(0))
25 | }
26 | }
27 | }
28 |
29 | func open(u *url.URL) error {
30 | if ok := js.Global().Call("open", u.String(), "_blank", "noreferrer,noopener").Truthy(); !ok {
31 | // If there's a error let's use the hacky way:
32 | // It will create a "fullscreen ", which clicking will
33 | // open the URL.
34 | // Generally, it will need two clicks to open the URL.
35 |
36 | // We can't hook into `a` (adding `a.addEvenetListener("click")` will make it fail again,
37 | // not sure why.
38 | // We remove this `a` when the app lost focus (based on Page Visibility API, which Gio relies on).
39 | a := _document.Call("createElement", "a")
40 | a.Set("href", u.String())
41 | a.Set("target", "_blank")
42 | a.Set("rel", "noreferrer,noopener")
43 | a.Set("innerText", " ")
44 | a.Get("classList").Call("add", "giohyperlink")
45 | a.Get("style").Set("display", "block")
46 | a.Get("style").Set("width", "100vw")
47 | a.Get("style").Set("height", "100vh")
48 | a.Get("style").Set("position", "fixed")
49 | a.Get("style").Set("top", "0")
50 | a.Get("style").Set("z-index", "100")
51 | _body.Call("appendChild", a)
52 | }
53 |
54 | return nil
55 | }
56 |
--------------------------------------------------------------------------------
/giohyperlink_unix.go:
--------------------------------------------------------------------------------
1 | // +build linux,!android openbsd freebsd netbsd dragonfly
2 |
3 | package giohyperlink
4 |
5 | import (
6 | "gioui.org/io/event"
7 | "net/url"
8 | "os/exec"
9 | )
10 |
11 | func listenEvents(_ event.Event) {
12 | // NO-OP
13 | }
14 |
15 | func open(u *url.URL) error {
16 | return exec.Command("xdg-open", u.String()).Run()
17 | }
18 |
--------------------------------------------------------------------------------
/giohyperlink_windows.go:
--------------------------------------------------------------------------------
1 | // +build windows
2 |
3 | package giohyperlink
4 |
5 | import (
6 | "gioui.org/io/event"
7 | "golang.org/x/sys/windows"
8 | "net/url"
9 | )
10 |
11 | func listenEvents(_ event.Event) {
12 | // NO-OP
13 | }
14 |
15 | func open(u *url.URL) error {
16 | return windows.ShellExecute(0, nil, windows.StringToUTF16Ptr(u.String()), nil, nil, windows.SW_SHOWNORMAL)
17 | }
18 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/inkeliz/giohyperlink
2 |
3 | go 1.18
4 |
5 | require (
6 | gioui.org v0.0.0-20220830130127-276b7eefdd65
7 | git.wow.st/gmp/jni v0.0.0-20200827154156-014cd5c7c4c0
8 | golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64
9 | )
10 |
11 | require (
12 | gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2 // indirect
13 | gioui.org/shader v1.0.6 // indirect
14 | github.com/benoitkugler/textlayout v0.1.3 // indirect
15 | github.com/gioui/uax v0.2.1-0.20220819135011-cda973fac06d // indirect
16 | github.com/go-text/typesetting v0.0.0-20220411150340-35994bc27a7b // indirect
17 | golang.org/x/exp/shiny v0.0.0-20220827204233-334a2380cb91 // indirect
18 | golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 // indirect
19 | golang.org/x/text v0.3.7 // indirect
20 | )
21 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | eliasnaur.com/font v0.0.0-20220124212145-832bb8fc08c3 h1:djFprmHZgrSepsHAIRMp5UJn3PzsoTg9drI+BDmif5Q=
2 | gioui.org v0.0.0-20220830130127-276b7eefdd65 h1:mX+A86TwTyHZNqDxekUukiAmtYNUOq4CnrRZHxUrlo8=
3 | gioui.org v0.0.0-20220830130127-276b7eefdd65/go.mod h1:GN091SCcGAfHfQiSOetXx7Abdy+8nmONj0ZN63Xxf7w=
4 | gioui.org/cpu v0.0.0-20210808092351-bfe733dd3334/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
5 | gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2 h1:AGDDxsJE1RpcXTAxPG2B4jrwVUJGFDjINIPi1jtO6pc=
6 | gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
7 | gioui.org/shader v1.0.6 h1:cvZmU+eODFR2545X+/8XucgZdTtEjR3QWW6W65b0q5Y=
8 | gioui.org/shader v1.0.6/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM=
9 | git.wow.st/gmp/jni v0.0.0-20200827154156-014cd5c7c4c0 h1:Ynp3h+TC8k1clvf45D28VFQlmy0bPx8M/MG5bB24Vj8=
10 | git.wow.st/gmp/jni v0.0.0-20200827154156-014cd5c7c4c0/go.mod h1:+axXBRUTIDlCeE73IKeD/os7LoEnTKdkp8/gQOFjqyo=
11 | github.com/benoitkugler/pstokenizer v1.0.0/go.mod h1:l1G2Voirz0q/jj0TQfabNxVsa8HZXh/VMxFSRALWTiE=
12 | github.com/benoitkugler/textlayout v0.0.5/go.mod h1:puH4v13Uz7uIhIH0XMk5jgc8U3MXcn5r3VlV9K8n0D8=
13 | github.com/benoitkugler/textlayout v0.1.3 h1:Jv0E28xDkke3KrWle90yOLtBmZsUqXLBy70lZRfbKN0=
14 | github.com/benoitkugler/textlayout v0.1.3/go.mod h1:o+1hFV+JSHBC9qNLIuwVoLedERU7sBPgEFcuSgfvi/w=
15 | github.com/benoitkugler/textlayout-testdata v0.1.1 h1:AvFxBxpfrQd8v55qH59mZOJOQjtD6K2SFe9/HvnIbJk=
16 | github.com/gioui/uax v0.2.1-0.20220819135011-cda973fac06d h1:ro1W5kY1pVBLHy4GokZUfr9cl7ewZhAiT5WsXqFDYE4=
17 | github.com/gioui/uax v0.2.1-0.20220819135011-cda973fac06d/go.mod h1:b6uGh9ySJPVQG/RdiI88bE5sUGDk6vzzRujv1BAeuJc=
18 | github.com/go-text/typesetting v0.0.0-20220411150340-35994bc27a7b h1:WINlj3ANt+CVrO2B4NGDHRlPvEWZPxjhb7z+JKypwXI=
19 | github.com/go-text/typesetting v0.0.0-20220411150340-35994bc27a7b/go.mod h1:ZNYu5saGoMOqtkVH5T8onTwhzenDUVszI+5WFHJRaxQ=
20 | golang.org/x/exp/shiny v0.0.0-20220827204233-334a2380cb91 h1:ryT6Nf0R83ZgD8WnFFdfI8wCeyqgdXWN4+CkFVNPAT0=
21 | golang.org/x/exp/shiny v0.0.0-20220827204233-334a2380cb91/go.mod h1:VjAR7z0ngyATZTELrBSkxOOHhhlnVUxDye4mcjx5h/8=
22 | golang.org/x/image v0.0.0-20210504121937-7319ad40d33e/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
23 | golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
24 | golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 h1:/eM0PCrQI2xd471rI+snWuu251/+/jpBpZqir2mPdnU=
25 | golang.org/x/image v0.0.0-20220722155232-062f8c9fd539/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
26 | golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
27 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
28 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
29 | golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 h1:UiNENfZ8gDvpiWw7IpOMQ27spWmThO1RwwdQVbJahJM=
30 | golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
31 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
32 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
33 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
34 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
35 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
36 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
37 |
--------------------------------------------------------------------------------