mirror of https://github.com/Hilbis/Hilbish
Compare commits
5 Commits
d99e056a76
...
c87fbe2b99
Author | SHA1 | Date |
---|---|---|
TorchedSammy | c87fbe2b99 | |
sammyette | 5bb6ba4aee | |
sammyette | 8d20ad9eed | |
sammyette | 71d23a4727 | |
sammyette | 6530d48b00 |
|
@ -6,3 +6,4 @@ docgen
|
||||||
|
|
||||||
.vim
|
.vim
|
||||||
petals/
|
petals/
|
||||||
|
.hugo_build.lock
|
||||||
|
|
|
@ -1,5 +1,13 @@
|
||||||
# 🎀 Changelog
|
# 🎀 Changelog
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
### Added
|
||||||
|
- Documented custom userdata types (Job and Timer Objects)
|
||||||
|
- Coming with fix is also adding the return types for some functions that were missing it
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- `hilbish.which` not working correctly with aliases
|
||||||
|
|
||||||
## [2.0.1] - 2022-12-28
|
## [2.0.1] - 2022-12-28
|
||||||
### Fixed
|
### Fixed
|
||||||
- Corrected documentation for hooks, removing outdated `command.no-perm`
|
- Corrected documentation for hooks, removing outdated `command.no-perm`
|
||||||
|
|
28
api.go
28
api.go
|
@ -231,8 +231,9 @@ func hlrun(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.PushingNext(t.Runtime, rt.IntValue(int64(exitcode)), rt.StringValue(stdoutStr), rt.StringValue(stderrStr)), nil
|
return c.PushingNext(t.Runtime, rt.IntValue(int64(exitcode)), rt.StringValue(stdoutStr), rt.StringValue(stderrStr)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// cwd()
|
// cwd() -> string
|
||||||
// Returns the current directory of the shell
|
// Returns the current directory of the shell
|
||||||
|
// --- @returns string
|
||||||
func hlcwd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func hlcwd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
cwd, _ := os.Getwd()
|
cwd, _ := os.Getwd()
|
||||||
|
|
||||||
|
@ -444,12 +445,12 @@ func hlgoro(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.Next(), nil
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// timeout(cb, time)
|
// timeout(cb, time) -> @Timer
|
||||||
// Runs the `cb` function after `time` in milliseconds
|
// Runs the `cb` function after `time` in milliseconds.
|
||||||
// Returns a `timer` object (see `doc timers`).
|
// This creates a timer that starts immediately.
|
||||||
// --- @param cb function
|
// --- @param cb function
|
||||||
// --- @param time number
|
// --- @param time number
|
||||||
// --- @returns table
|
// --- @returns Timer
|
||||||
func hltimeout(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func hltimeout(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
if err := c.CheckNArgs(2); err != nil {
|
if err := c.CheckNArgs(2); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -470,12 +471,12 @@ func hltimeout(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.PushingNext1(t.Runtime, rt.UserDataValue(timer.ud)), nil
|
return c.PushingNext1(t.Runtime, rt.UserDataValue(timer.ud)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// interval(cb, time)
|
// interval(cb, time) -> @Timer
|
||||||
// Runs the `cb` function every `time` milliseconds.
|
// Runs the `cb` function every `time` milliseconds.
|
||||||
// Returns a `timer` object (see `doc timers`).
|
// This creates a timer that starts immediately.
|
||||||
// --- @param cb function
|
// --- @param cb function
|
||||||
// --- @param time number
|
// --- @param time number
|
||||||
// --- @return table
|
// --- @return Timer
|
||||||
func hlinterval(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func hlinterval(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
if err := c.CheckNArgs(2); err != nil {
|
if err := c.CheckNArgs(2); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -536,9 +537,11 @@ func hlprependPath(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.Next(), nil
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// which(name)
|
// which(name) -> string
|
||||||
// Checks if `name` is a valid command
|
// Checks if `name` is a valid command.
|
||||||
|
// Will return the path of the binary, or a basename if it's a commander.
|
||||||
// --- @param name string
|
// --- @param name string
|
||||||
|
// --- @returns string
|
||||||
func hlwhich(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func hlwhich(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
if err := c.Check1Arg(); err != nil {
|
if err := c.Check1Arg(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -548,7 +551,10 @@ func hlwhich(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := aliases.Resolve(name)
|
// itll return either the original command or what was passed
|
||||||
|
// if name isnt empty its not an issue
|
||||||
|
alias := aliases.Resolve(name)
|
||||||
|
cmd := strings.Split(alias, " ")[0]
|
||||||
|
|
||||||
// check for commander
|
// check for commander
|
||||||
if commands[cmd] != nil {
|
if commands[cmd] != nil {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"go/doc"
|
"go/doc"
|
||||||
"go/parser"
|
"go/parser"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -31,6 +32,7 @@ type emmyPiece struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type module struct {
|
type module struct {
|
||||||
|
Types []docPiece
|
||||||
Docs []docPiece
|
Docs []docPiece
|
||||||
Fields []docPiece
|
Fields []docPiece
|
||||||
Properties []docPiece
|
Properties []docPiece
|
||||||
|
@ -38,6 +40,7 @@ type module struct {
|
||||||
Description string
|
Description string
|
||||||
ParentModule string
|
ParentModule string
|
||||||
HasInterfaces bool
|
HasInterfaces bool
|
||||||
|
HasTypes bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type docPiece struct {
|
type docPiece struct {
|
||||||
|
@ -49,6 +52,7 @@ type docPiece struct {
|
||||||
GoFuncName string
|
GoFuncName string
|
||||||
IsInterface bool
|
IsInterface bool
|
||||||
IsMember bool
|
IsMember bool
|
||||||
|
IsType bool
|
||||||
Fields []docPiece
|
Fields []docPiece
|
||||||
Properties []docPiece
|
Properties []docPiece
|
||||||
}
|
}
|
||||||
|
@ -61,6 +65,7 @@ type tag struct {
|
||||||
var docs = make(map[string]module)
|
var docs = make(map[string]module)
|
||||||
var interfaceDocs = make(map[string]module)
|
var interfaceDocs = make(map[string]module)
|
||||||
var emmyDocs = make(map[string][]emmyPiece)
|
var emmyDocs = make(map[string][]emmyPiece)
|
||||||
|
var typeTable = make(map[string][]string) // [0] = parentMod, [1] = interfaces
|
||||||
var prefix = map[string]string{
|
var prefix = map[string]string{
|
||||||
"main": "hl",
|
"main": "hl",
|
||||||
"hilbish": "hl",
|
"hilbish": "hl",
|
||||||
|
@ -119,6 +124,71 @@ func docPieceTag(tagName string, tags map[string][]tag) []docPiece {
|
||||||
return dps
|
return dps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setupDocType(mod string, typ *doc.Type) *docPiece {
|
||||||
|
docs := strings.TrimSpace(typ.Doc)
|
||||||
|
inInterface := strings.HasPrefix(docs, "#interface")
|
||||||
|
if !inInterface {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
tags, doc := getTagsAndDocs(docs)
|
||||||
|
|
||||||
|
var interfaces string
|
||||||
|
typeName := strings.ToUpper(string(typ.Name[0])) + typ.Name[1:]
|
||||||
|
typeDoc := []string{}
|
||||||
|
|
||||||
|
if inInterface {
|
||||||
|
interfaces = tags["interface"][0].id
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := docPieceTag("field", tags)
|
||||||
|
properties := docPieceTag("property", tags)
|
||||||
|
|
||||||
|
for _, d := range doc {
|
||||||
|
if strings.HasPrefix(d, "---") {
|
||||||
|
// TODO: document types in lua
|
||||||
|
/*
|
||||||
|
emmyLine := strings.TrimSpace(strings.TrimPrefix(d, "---"))
|
||||||
|
emmyLinePieces := strings.Split(emmyLine, " ")
|
||||||
|
emmyType := emmyLinePieces[0]
|
||||||
|
if emmyType == "@param" {
|
||||||
|
em.Params = append(em.Params, emmyLinePieces[1])
|
||||||
|
}
|
||||||
|
if emmyType == "@vararg" {
|
||||||
|
em.Params = append(em.Params, "...") // add vararg
|
||||||
|
}
|
||||||
|
em.Annotations = append(em.Annotations, d)
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
typeDoc = append(typeDoc, d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var isMember bool
|
||||||
|
if tags["member"] != nil {
|
||||||
|
isMember = true
|
||||||
|
}
|
||||||
|
var parentMod string
|
||||||
|
if inInterface {
|
||||||
|
parentMod = mod
|
||||||
|
}
|
||||||
|
dps := &docPiece{
|
||||||
|
Doc: typeDoc,
|
||||||
|
FuncName: typeName,
|
||||||
|
Interfacing: interfaces,
|
||||||
|
IsInterface: inInterface,
|
||||||
|
IsMember: isMember,
|
||||||
|
IsType: true,
|
||||||
|
ParentModule: parentMod,
|
||||||
|
Fields: fields,
|
||||||
|
Properties: properties,
|
||||||
|
}
|
||||||
|
|
||||||
|
typeTable[strings.ToLower(typeName)] = []string{parentMod, interfaces}
|
||||||
|
|
||||||
|
return dps
|
||||||
|
}
|
||||||
|
|
||||||
func setupDoc(mod string, fun *doc.Func) *docPiece {
|
func setupDoc(mod string, fun *doc.Func) *docPiece {
|
||||||
docs := strings.TrimSpace(fun.Doc)
|
docs := strings.TrimSpace(fun.Doc)
|
||||||
inInterface := strings.HasPrefix(docs, "#interface")
|
inInterface := strings.HasPrefix(docs, "#interface")
|
||||||
|
@ -220,6 +290,7 @@ func main() {
|
||||||
for l, f := range pkgs {
|
for l, f := range pkgs {
|
||||||
p := doc.New(f, "./", doc.AllDecls)
|
p := doc.New(f, "./", doc.AllDecls)
|
||||||
pieces := []docPiece{}
|
pieces := []docPiece{}
|
||||||
|
typePieces := []docPiece{}
|
||||||
mod := l
|
mod := l
|
||||||
if mod == "main" {
|
if mod == "main" {
|
||||||
mod = "hilbish"
|
mod = "hilbish"
|
||||||
|
@ -237,6 +308,14 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, t := range p.Types {
|
for _, t := range p.Types {
|
||||||
|
typePiece := setupDocType(mod, t)
|
||||||
|
if typePiece != nil {
|
||||||
|
typePieces = append(typePieces, *typePiece)
|
||||||
|
if typePiece.IsInterface {
|
||||||
|
hasInterfaces = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, m := range t.Methods {
|
for _, m := range t.Methods {
|
||||||
piece := setupDoc(mod, m)
|
piece := setupDoc(mod, m)
|
||||||
if piece == nil {
|
if piece == nil {
|
||||||
|
@ -254,6 +333,7 @@ func main() {
|
||||||
shortDesc := descParts[0]
|
shortDesc := descParts[0]
|
||||||
desc := descParts[1:]
|
desc := descParts[1:]
|
||||||
filteredPieces := []docPiece{}
|
filteredPieces := []docPiece{}
|
||||||
|
filteredTypePieces := []docPiece{}
|
||||||
for _, piece := range pieces {
|
for _, piece := range pieces {
|
||||||
if !piece.IsInterface {
|
if !piece.IsInterface {
|
||||||
filteredPieces = append(filteredPieces, piece)
|
filteredPieces = append(filteredPieces, piece)
|
||||||
|
@ -276,10 +356,28 @@ func main() {
|
||||||
interfaceModules[modname].Properties = piece.Properties
|
interfaceModules[modname].Properties = piece.Properties
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
interfaceModules[modname].Docs = append(interfaceModules[modname].Docs, piece)
|
interfaceModules[modname].Docs = append(interfaceModules[modname].Docs, piece)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, piece := range typePieces {
|
||||||
|
if !piece.IsInterface {
|
||||||
|
filteredTypePieces = append(filteredTypePieces, piece)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
modname := piece.ParentModule + "." + piece.Interfacing
|
||||||
|
if interfaceModules[modname] == nil {
|
||||||
|
interfaceModules[modname] = &module{
|
||||||
|
ParentModule: piece.ParentModule,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interfaceModules[modname].Types = append(interfaceModules[modname].Types, piece)
|
||||||
|
}
|
||||||
|
|
||||||
docs[mod] = module{
|
docs[mod] = module{
|
||||||
|
Types: filteredTypePieces,
|
||||||
Docs: filteredPieces,
|
Docs: filteredPieces,
|
||||||
ShortDescription: shortDesc,
|
ShortDescription: shortDesc,
|
||||||
Description: strings.Join(desc, "\n"),
|
Description: strings.Join(desc, "\n"),
|
||||||
|
@ -335,17 +433,71 @@ func main() {
|
||||||
}
|
}
|
||||||
f.WriteString("\n")
|
f.WriteString("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(modu.Docs) != 0 {
|
if len(modu.Docs) != 0 {
|
||||||
|
typeTag, _ := regexp.Compile(`@\w+`)
|
||||||
f.WriteString("## Functions\n")
|
f.WriteString("## Functions\n")
|
||||||
|
for _, dps := range modu.Docs {
|
||||||
|
if dps.IsMember {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
htmlSig := typeTag.ReplaceAllStringFunc(strings.Replace(dps.FuncSig, "<", `\<`, -1), func(typ string) string {
|
||||||
|
typName := typ[1:]
|
||||||
|
typLookup := typeTable[strings.ToLower(typName)]
|
||||||
|
linkedTyp := fmt.Sprintf("/Hilbish/docs/api/%s/%s/#%s", typLookup[0], typLookup[0] + "." + typLookup[1], strings.ToLower(typName))
|
||||||
|
return fmt.Sprintf(`<a href="%s" style="text-decoration: none;">%s</a>`, linkedTyp, typName)
|
||||||
|
})
|
||||||
|
f.WriteString(fmt.Sprintf("### %s\n", htmlSig))
|
||||||
|
for _, doc := range dps.Doc {
|
||||||
|
if !strings.HasPrefix(doc, "---") {
|
||||||
|
f.WriteString(doc + "\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.WriteString("\n")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for _, dps := range modu.Docs {
|
|
||||||
f.WriteString(fmt.Sprintf("### %s\n", dps.FuncSig))
|
if len(modu.Types) != 0 {
|
||||||
for _, doc := range dps.Doc {
|
f.WriteString("## Types\n")
|
||||||
if !strings.HasPrefix(doc, "---") {
|
for _, dps := range modu.Types {
|
||||||
f.WriteString(doc + "\n")
|
f.WriteString(fmt.Sprintf("## %s\n", dps.FuncName))
|
||||||
|
for _, doc := range dps.Doc {
|
||||||
|
if !strings.HasPrefix(doc, "---") {
|
||||||
|
f.WriteString(doc + "\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(dps.Properties) != 0 {
|
||||||
|
f.WriteString("### Properties\n")
|
||||||
|
for _, dps := range dps.Properties {
|
||||||
|
f.WriteString(fmt.Sprintf("- `%s`: ", dps.FuncName))
|
||||||
|
f.WriteString(strings.Join(dps.Doc, " "))
|
||||||
|
f.WriteString("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.WriteString("\n")
|
||||||
|
typeTag, _ := regexp.Compile(`@\w+`)
|
||||||
|
|
||||||
|
f.WriteString("### Methods\n")
|
||||||
|
for _, dps := range modu.Docs {
|
||||||
|
if !dps.IsMember {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
htmlSig := typeTag.ReplaceAllStringFunc(strings.Replace(dps.FuncSig, "<", `\<`, -1), func(typ string) string {
|
||||||
|
// todo: get type from global table to link to
|
||||||
|
// other pages (hilbish page can link to hilbish.jobs#Job)
|
||||||
|
typName := typ[1:]
|
||||||
|
linkedTyp := strings.ToLower(typName) // TODO: link
|
||||||
|
return fmt.Sprintf(`<a href="#%s" style="text-decoration: none;">%s</a>`, linkedTyp, typName)
|
||||||
|
})
|
||||||
|
f.WriteString(fmt.Sprintf("#### %s\n", htmlSig))
|
||||||
|
for _, doc := range dps.Doc {
|
||||||
|
if !strings.HasPrefix(doc, "---") {
|
||||||
|
f.WriteString(doc + "\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.WriteString("\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.WriteString("\n")
|
|
||||||
}
|
}
|
||||||
}(mod, docPath, v)
|
}(mod, docPath, v)
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ replacing <cmd> with the name of the command (for example `command.git`).
|
||||||
`cb` must be a function that returns a table of "completion groups."
|
`cb` must be a function that returns a table of "completion groups."
|
||||||
Check `doc completions` for more information.
|
Check `doc completions` for more information.
|
||||||
|
|
||||||
### cwd()
|
### cwd() -> string
|
||||||
Returns the current directory of the shell
|
Returns the current directory of the shell
|
||||||
|
|
||||||
### exec(cmd)
|
### exec(cmd)
|
||||||
|
@ -60,9 +60,9 @@ override this function with your custom handler.
|
||||||
### inputMode(mode)
|
### inputMode(mode)
|
||||||
Sets the input mode for Hilbish's line reader. Accepts either emacs or vim
|
Sets the input mode for Hilbish's line reader. Accepts either emacs or vim
|
||||||
|
|
||||||
### interval(cb, time)
|
### interval(cb, time) -> <a href="/Hilbish/docs/api/hilbish/hilbish.timers/#timer" style="text-decoration: none;">Timer</a>
|
||||||
Runs the `cb` function every `time` milliseconds.
|
Runs the `cb` function every `time` milliseconds.
|
||||||
Returns a `timer` object (see `doc timers`).
|
This creates a timer that starts immediately.
|
||||||
|
|
||||||
### multiprompt(str)
|
### multiprompt(str)
|
||||||
Changes the continued line prompt to `str`
|
Changes the continued line prompt to `str`
|
||||||
|
@ -95,10 +95,11 @@ Accepted values for mode are hybrid (the default), hybridRev (sh first then Lua)
|
||||||
sh, and lua. It also accepts a function, to which if it is passed one
|
sh, and lua. It also accepts a function, to which if it is passed one
|
||||||
will call it to execute user input instead.
|
will call it to execute user input instead.
|
||||||
|
|
||||||
### timeout(cb, time)
|
### timeout(cb, time) -> <a href="/Hilbish/docs/api/hilbish/hilbish.timers/#timer" style="text-decoration: none;">Timer</a>
|
||||||
Runs the `cb` function after `time` in milliseconds
|
Runs the `cb` function after `time` in milliseconds.
|
||||||
Returns a `timer` object (see `doc timers`).
|
This creates a timer that starts immediately.
|
||||||
|
|
||||||
### which(name)
|
### which(name) -> string
|
||||||
Checks if `name` is a valid command
|
Checks if `name` is a valid command.
|
||||||
|
Will return the path of the binary, or a basename if it's a commander.
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ This is an alias (ha) for the `hilbish.alias` function.
|
||||||
### delete(name)
|
### delete(name)
|
||||||
Removes an alias.
|
Removes an alias.
|
||||||
|
|
||||||
### list() -> table<string, string>
|
### list() -> table\<string, string>
|
||||||
Get a table of all aliases, with string keys as the alias and the value as the command.
|
Get a table of all aliases, with string keys as the alias and the value as the command.
|
||||||
|
|
||||||
### resolve(alias) -> command (string)
|
### resolve(alias) -> command (string)
|
||||||
|
|
|
@ -14,7 +14,26 @@ Manage interactive jobs in Hilbish via Lua.
|
||||||
Jobs are the name of background tasks/commands. A job can be started via
|
Jobs are the name of background tasks/commands. A job can be started via
|
||||||
interactive usage or with the functions defined below for use in external runners.
|
interactive usage or with the functions defined below for use in external runners.
|
||||||
|
|
||||||
## Object properties
|
## Functions
|
||||||
|
### add(cmdstr, args, execPath)
|
||||||
|
Adds a new job to the job table. Note that this does not immediately run it.
|
||||||
|
|
||||||
|
### all() -> table\<<a href="/Hilbish/docs/api/hilbish/hilbish.jobs/#job" style="text-decoration: none;">Job</a>>
|
||||||
|
Returns a table of all job objects.
|
||||||
|
|
||||||
|
### disown(id)
|
||||||
|
Disowns a job. This deletes it from the job table.
|
||||||
|
|
||||||
|
### get(id) -> <a href="/Hilbish/docs/api/hilbish/hilbish.jobs/#job" style="text-decoration: none;">Job</a>
|
||||||
|
Get a job object via its ID.
|
||||||
|
|
||||||
|
### last() -> <a href="/Hilbish/docs/api/hilbish/hilbish.jobs/#job" style="text-decoration: none;">Job</a>
|
||||||
|
Returns the last added job from the table.
|
||||||
|
|
||||||
|
## Types
|
||||||
|
## Job
|
||||||
|
The Job type describes a Hilbish job.
|
||||||
|
### Properties
|
||||||
- `cmd`: The user entered command string for the job.
|
- `cmd`: The user entered command string for the job.
|
||||||
- `running`: Whether the job is running or not.
|
- `running`: Whether the job is running or not.
|
||||||
- `id`: The ID of the job in the job table
|
- `id`: The ID of the job in the job table
|
||||||
|
@ -23,32 +42,17 @@ interactive usage or with the functions defined below for use in external runner
|
||||||
- `stdout`: The standard output of the job. This just means the normal logs of the process.
|
- `stdout`: The standard output of the job. This just means the normal logs of the process.
|
||||||
- `stderr`: The standard error stream of the process. This (usually) includes error messages of the job.
|
- `stderr`: The standard error stream of the process. This (usually) includes error messages of the job.
|
||||||
|
|
||||||
## Functions
|
### Methods
|
||||||
### background()
|
#### background()
|
||||||
Puts a job in the background. This acts the same as initially running a job.
|
Puts a job in the background. This acts the same as initially running a job.
|
||||||
|
|
||||||
### foreground()
|
#### foreground()
|
||||||
Puts a job in the foreground. This will cause it to run like it was
|
Puts a job in the foreground. This will cause it to run like it was
|
||||||
executed normally and wait for it to complete.
|
executed normally and wait for it to complete.
|
||||||
|
|
||||||
### start()
|
#### start()
|
||||||
Starts running the job.
|
Starts running the job.
|
||||||
|
|
||||||
### stop()
|
#### stop()
|
||||||
Stops the job from running.
|
Stops the job from running.
|
||||||
|
|
||||||
### add(cmdstr, args, execPath)
|
|
||||||
Adds a new job to the job table. Note that this does not immediately run it.
|
|
||||||
|
|
||||||
### all() -> jobs (table<Job/Table>)
|
|
||||||
Returns a table of all job objects.
|
|
||||||
|
|
||||||
### disown(id)
|
|
||||||
Disowns a job. This deletes it from the job table.
|
|
||||||
|
|
||||||
### get(id) -> job (Job/Table)
|
|
||||||
Get a job object via its ID.
|
|
||||||
|
|
||||||
### last() -> job (Job/Table)
|
|
||||||
Returns the last added job from the table.
|
|
||||||
|
|
||||||
|
|
|
@ -22,35 +22,38 @@ All functions documented with the `Timer` type refer to a Timer object.
|
||||||
|
|
||||||
An example of usage:
|
An example of usage:
|
||||||
```
|
```
|
||||||
local t = hilbish.timers.create(1, 5000, function()
|
local t = hilbish.timers.create(hilbish.timers.TIMEOUT, 5000, function()
|
||||||
print 'hello!'
|
print 'hello!'
|
||||||
end)
|
end)
|
||||||
|
|
||||||
t:stop()
|
|
||||||
print(t.running, t.duration, t.type)
|
|
||||||
t:start()
|
t:start()
|
||||||
|
print(t.running) // true
|
||||||
```
|
```
|
||||||
|
|
||||||
## Interface fields
|
## Interface fields
|
||||||
- `INTERVAL`: Constant for an interval timer type
|
- `INTERVAL`: Constant for an interval timer type
|
||||||
- `TIMEOUT`: Constant for a timeout timer type
|
- `TIMEOUT`: Constant for a timeout timer type
|
||||||
|
|
||||||
## Object properties
|
## Functions
|
||||||
|
### create(type, time, callback) -> <a href="/Hilbish/docs/api/hilbish/hilbish.timers/#timer" style="text-decoration: none;">Timer</a>
|
||||||
|
Creates a timer that runs based on the specified `time` in milliseconds.
|
||||||
|
The `type` can either be `hilbish.timers.INTERVAL` or `hilbish.timers.TIMEOUT`
|
||||||
|
|
||||||
|
### get(id) -> <a href="/Hilbish/docs/api/hilbish/hilbish.timers/#timer" style="text-decoration: none;">Timer</a>
|
||||||
|
Retrieves a timer via its ID.
|
||||||
|
|
||||||
|
## Types
|
||||||
|
## Timer
|
||||||
|
The Job type describes a Hilbish timer.
|
||||||
|
### Properties
|
||||||
- `type`: What type of timer it is
|
- `type`: What type of timer it is
|
||||||
- `running`: If the timer is running
|
- `running`: If the timer is running
|
||||||
- `duration`: The duration in milliseconds that the timer will run
|
- `duration`: The duration in milliseconds that the timer will run
|
||||||
|
|
||||||
## Functions
|
### Methods
|
||||||
### start()
|
#### start()
|
||||||
Starts a timer.
|
Starts a timer.
|
||||||
|
|
||||||
### stop()
|
#### stop()
|
||||||
Stops a timer.
|
Stops a timer.
|
||||||
|
|
||||||
### create(type, time, callback)
|
|
||||||
Creates a timer that runs based on the specified `time` in milliseconds.
|
|
||||||
The `type` can either be `hilbish.timers.INTERVAL` or `hilbish.timers.TIMEOUT`
|
|
||||||
|
|
||||||
### get(id) -> timer (Timer/Table)
|
|
||||||
Retrieves a timer via its ID.
|
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,7 @@ function hilbish.appendPath(dir) end
|
||||||
function hilbish.complete(scope, cb) end
|
function hilbish.complete(scope, cb) end
|
||||||
|
|
||||||
--- Returns the current directory of the shell
|
--- Returns the current directory of the shell
|
||||||
|
--- @returns string
|
||||||
function hilbish.cwd() end
|
function hilbish.cwd() end
|
||||||
|
|
||||||
--- Replaces running hilbish with `cmd`
|
--- Replaces running hilbish with `cmd`
|
||||||
|
@ -94,10 +95,10 @@ function hilbish.hinter(line, pos) end
|
||||||
function hilbish.inputMode(mode) end
|
function hilbish.inputMode(mode) end
|
||||||
|
|
||||||
--- Runs the `cb` function every `time` milliseconds.
|
--- Runs the `cb` function every `time` milliseconds.
|
||||||
--- Returns a `timer` object (see `doc timers`).
|
--- This creates a timer that starts immediately.
|
||||||
--- @param cb function
|
--- @param cb function
|
||||||
--- @param time number
|
--- @param time number
|
||||||
--- @return table
|
--- @return Timer
|
||||||
function hilbish.interval(cb, time) end
|
function hilbish.interval(cb, time) end
|
||||||
|
|
||||||
--- Changes the continued line prompt to `str`
|
--- Changes the continued line prompt to `str`
|
||||||
|
@ -141,15 +142,17 @@ function hilbish.run(cmd, returnOut) end
|
||||||
--- @param mode string|function
|
--- @param mode string|function
|
||||||
function hilbish.runnerMode(mode) end
|
function hilbish.runnerMode(mode) end
|
||||||
|
|
||||||
--- Runs the `cb` function after `time` in milliseconds
|
--- Runs the `cb` function after `time` in milliseconds.
|
||||||
--- Returns a `timer` object (see `doc timers`).
|
--- This creates a timer that starts immediately.
|
||||||
--- @param cb function
|
--- @param cb function
|
||||||
--- @param time number
|
--- @param time number
|
||||||
--- @returns table
|
--- @returns Timer
|
||||||
function hilbish.timeout(cb, time) end
|
function hilbish.timeout(cb, time) end
|
||||||
|
|
||||||
--- Checks if `name` is a valid command
|
--- Checks if `name` is a valid command.
|
||||||
|
--- Will return the path of the binary, or a basename if it's a commander.
|
||||||
--- @param name string
|
--- @param name string
|
||||||
|
--- @returns string
|
||||||
function hilbish.which(name) end
|
function hilbish.which(name) end
|
||||||
|
|
||||||
--- Puts a job in the background. This acts the same as initially running a job.
|
--- Puts a job in the background. This acts the same as initially running a job.
|
||||||
|
@ -180,7 +183,7 @@ function hilbish.runner.lua(cmd) end
|
||||||
function hilbish.jobs:start() end
|
function hilbish.jobs:start() end
|
||||||
|
|
||||||
--- Stops the job from running.
|
--- Stops the job from running.
|
||||||
function hilbish.jobs.stop() end
|
function hilbish.jobs:stop() end
|
||||||
|
|
||||||
--- Runs a command in Hilbish's shell script interpreter.
|
--- Runs a command in Hilbish's shell script interpreter.
|
||||||
--- This is the equivalent of using `source`.
|
--- This is the equivalent of using `source`.
|
||||||
|
|
23
job.go
23
job.go
|
@ -18,6 +18,15 @@ import (
|
||||||
var jobs *jobHandler
|
var jobs *jobHandler
|
||||||
var jobMetaKey = rt.StringValue("hshjob")
|
var jobMetaKey = rt.StringValue("hshjob")
|
||||||
|
|
||||||
|
// #interface jobs
|
||||||
|
// #property cmd The user entered command string for the job.
|
||||||
|
// #property running Whether the job is running or not.
|
||||||
|
// #property id The ID of the job in the job table
|
||||||
|
// #property pid The Process ID
|
||||||
|
// #property exitCode The last exit code of the job.
|
||||||
|
// #property stdout The standard output of the job. This just means the normal logs of the process.
|
||||||
|
// #property stderr The standard error stream of the process. This (usually) includes error messages of the job.
|
||||||
|
// The Job type describes a Hilbish job.
|
||||||
type job struct {
|
type job struct {
|
||||||
cmd string
|
cmd string
|
||||||
running bool
|
running bool
|
||||||
|
@ -135,6 +144,7 @@ func luaStartJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// #interface jobs
|
// #interface jobs
|
||||||
|
// #member
|
||||||
// stop()
|
// stop()
|
||||||
// Stops the job from running.
|
// Stops the job from running.
|
||||||
func luaStopJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func luaStopJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
@ -293,13 +303,6 @@ func (j *jobHandler) stopAll() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// #interface jobs
|
// #interface jobs
|
||||||
// #property cmd The user entered command string for the job.
|
|
||||||
// #property running Whether the job is running or not.
|
|
||||||
// #property id The ID of the job in the job table
|
|
||||||
// #property pid The Process ID
|
|
||||||
// #property exitCode The last exit code of the job.
|
|
||||||
// #property stdout The standard output of the job. This just means the normal logs of the process.
|
|
||||||
// #property stderr The standard error stream of the process. This (usually) includes error messages of the job.
|
|
||||||
// background job management
|
// background job management
|
||||||
/*
|
/*
|
||||||
Manage interactive jobs in Hilbish via Lua.
|
Manage interactive jobs in Hilbish via Lua.
|
||||||
|
@ -384,7 +387,7 @@ func jobUserData(j *job) *rt.UserData {
|
||||||
}
|
}
|
||||||
|
|
||||||
// #interface jobs
|
// #interface jobs
|
||||||
// get(id) -> job (Job/Table)
|
// get(id) -> @Job
|
||||||
// Get a job object via its ID.
|
// Get a job object via its ID.
|
||||||
// --- @param id number
|
// --- @param id number
|
||||||
// --- @returns Job
|
// --- @returns Job
|
||||||
|
@ -444,7 +447,7 @@ func (j *jobHandler) luaAddJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// #interface jobs
|
// #interface jobs
|
||||||
// all() -> jobs (table<Job/Table>)
|
// all() -> table<@Job>
|
||||||
// Returns a table of all job objects.
|
// Returns a table of all job objects.
|
||||||
// --- @returns table<Job>
|
// --- @returns table<Job>
|
||||||
func (j *jobHandler) luaAllJobs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func (j *jobHandler) luaAllJobs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
@ -481,7 +484,7 @@ func (j *jobHandler) luaDisownJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// #interface jobs
|
// #interface jobs
|
||||||
// last() -> job (Job/Table)
|
// last() -> @Job
|
||||||
// Returns the last added job from the table.
|
// Returns the last added job from the table.
|
||||||
// --- @returns Job
|
// --- @returns Job
|
||||||
func (j *jobHandler) luaLastJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func (j *jobHandler) luaLastJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
|
|
@ -15,6 +15,16 @@ commander.register('doc', function(args)
|
||||||
|
|
||||||
]]
|
]]
|
||||||
|
|
||||||
|
local modules = table.map(fs.readdir(moddocPath), function(f)
|
||||||
|
return lunacolors.underline(lunacolors.blue(string.gsub(f, '.md', '')))
|
||||||
|
end)
|
||||||
|
local doc = [[
|
||||||
|
Welcome to Hilbish's documentation viewer! Here you can find
|
||||||
|
documentation for builtin functions and other things related
|
||||||
|
to Hilbish.
|
||||||
|
|
||||||
|
Usage: doc <section> [subdoc]
|
||||||
|
Available sections: ]] .. table.concat(modules, ', ')
|
||||||
if #args > 0 then
|
if #args > 0 then
|
||||||
local mod = args[1]
|
local mod = args[1]
|
||||||
|
|
||||||
|
@ -43,7 +53,7 @@ commander.register('doc', function(args)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
funcdocs = f:read '*a':gsub('-([%d]+)', '%1')
|
funcdocs = f:read '*a':gsub('-([%d]+)', '%1')
|
||||||
local moddocs = table.filter(fs.readdir(moddocPath), function(f) return f ~= '_index.md' end)
|
local moddocs = table.filter(fs.readdir(moddocPath), function(f) return f ~= '_index.md' or f ~= 'index.md' end)
|
||||||
local subdocs = table.map(moddocs, function(fname)
|
local subdocs = table.map(moddocs, function(fname)
|
||||||
return lunacolors.underline(lunacolors.blue(string.gsub(fname, '.md', '')))
|
return lunacolors.underline(lunacolors.blue(string.gsub(fname, '.md', '')))
|
||||||
end)
|
end)
|
||||||
|
@ -71,35 +81,20 @@ commander.register('doc', function(args)
|
||||||
if mod == 'api' then
|
if mod == 'api' then
|
||||||
funcdocs = string.format(apidocHeader, vals.title, vals.description or 'no description.') .. funcdocs
|
funcdocs = string.format(apidocHeader, vals.title, vals.description or 'no description.') .. funcdocs
|
||||||
end
|
end
|
||||||
local backtickOccurence = 0
|
doc = funcdocs:sub(1, #funcdocs - 1)
|
||||||
local formattedFuncs = lunacolors.format(funcdocs:sub(1, #funcdocs - 1):gsub('`', function()
|
|
||||||
backtickOccurence = backtickOccurence + 1
|
|
||||||
if backtickOccurence % 2 == 0 then
|
|
||||||
return '{reset}'
|
|
||||||
else
|
|
||||||
return '{underline}{green}'
|
|
||||||
end
|
|
||||||
end):gsub('#+.-\n', function(t)
|
|
||||||
return '{bold}{magenta}' .. t .. '{reset}'
|
|
||||||
end))
|
|
||||||
print(formattedFuncs)
|
|
||||||
f:close()
|
f:close()
|
||||||
|
|
||||||
return
|
|
||||||
end
|
end
|
||||||
local modules = table.map(fs.readdir(moddocPath), function(f)
|
|
||||||
return lunacolors.underline(lunacolors.blue(string.gsub(f, '.md', '')))
|
|
||||||
end)
|
|
||||||
|
|
||||||
io.write [[
|
local backtickOccurence = 0
|
||||||
Welcome to Hilbish's doc tool! Here you can find documentation for builtin
|
print(lunacolors.format(doc:gsub('`', function()
|
||||||
functions and other things.
|
backtickOccurence = backtickOccurence + 1
|
||||||
|
if backtickOccurence % 2 == 0 then
|
||||||
Usage: doc <section> [subdoc]
|
return '{reset}'
|
||||||
A section is a module or a literal section and a subdoc is a subsection for it.
|
else
|
||||||
|
return '{underline}{green}'
|
||||||
Available sections: ]]
|
end
|
||||||
io.flush()
|
end):gsub('#+.-\n', function(t)
|
||||||
|
local signature = t:gsub('<.->(.-)</.->', '{underline}%1'):gsub('\\', '<')
|
||||||
print(table.concat(modules, ', '))
|
return '{bold}{yellow}' .. signature .. '{reset}'
|
||||||
|
end)))
|
||||||
end)
|
end)
|
||||||
|
|
5
timer.go
5
timer.go
|
@ -15,6 +15,11 @@ const (
|
||||||
timerTimeout
|
timerTimeout
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// #interface timers
|
||||||
|
// #property type What type of timer it is
|
||||||
|
// #property running If the timer is running
|
||||||
|
// #property duration The duration in milliseconds that the timer will run
|
||||||
|
// The Job type describes a Hilbish timer.
|
||||||
type timer struct{
|
type timer struct{
|
||||||
id int
|
id int
|
||||||
typ timerType
|
typ timerType
|
||||||
|
|
|
@ -62,7 +62,7 @@ func (th *timersModule) get(id int) *timer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// #interface timers
|
// #interface timers
|
||||||
// create(type, time, callback)
|
// create(type, time, callback) -> @Timer
|
||||||
// Creates a timer that runs based on the specified `time` in milliseconds.
|
// Creates a timer that runs based on the specified `time` in milliseconds.
|
||||||
// The `type` can either be `hilbish.timers.INTERVAL` or `hilbish.timers.TIMEOUT`
|
// The `type` can either be `hilbish.timers.INTERVAL` or `hilbish.timers.TIMEOUT`
|
||||||
// --- @param type number
|
// --- @param type number
|
||||||
|
@ -91,7 +91,7 @@ func (th *timersModule) luaCreate(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// #interface timers
|
// #interface timers
|
||||||
// get(id) -> timer (Timer/Table)
|
// get(id) -> @Timer
|
||||||
// Retrieves a timer via its ID.
|
// Retrieves a timer via its ID.
|
||||||
// --- @param id number
|
// --- @param id number
|
||||||
// --- @returns Timer
|
// --- @returns Timer
|
||||||
|
@ -115,9 +115,6 @@ func (th *timersModule) luaGet(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
// #interface timers
|
// #interface timers
|
||||||
// #field INTERVAL Constant for an interval timer type
|
// #field INTERVAL Constant for an interval timer type
|
||||||
// #field TIMEOUT Constant for a timeout timer type
|
// #field TIMEOUT Constant for a timeout timer type
|
||||||
// #property type What type of timer it is
|
|
||||||
// #property running If the timer is running
|
|
||||||
// #property duration The duration in milliseconds that the timer will run
|
|
||||||
// timeout and interval API
|
// timeout and interval API
|
||||||
/*
|
/*
|
||||||
If you ever want to run a piece of code on a timed interval, or want to wait
|
If you ever want to run a piece of code on a timed interval, or want to wait
|
||||||
|
@ -134,13 +131,12 @@ All functions documented with the `Timer` type refer to a Timer object.
|
||||||
|
|
||||||
An example of usage:
|
An example of usage:
|
||||||
```
|
```
|
||||||
local t = hilbish.timers.create(1, 5000, function()
|
local t = hilbish.timers.create(hilbish.timers.TIMEOUT, 5000, function()
|
||||||
print 'hello!'
|
print 'hello!'
|
||||||
end)
|
end)
|
||||||
|
|
||||||
t:stop()
|
|
||||||
print(t.running, t.duration, t.type)
|
|
||||||
t:start()
|
t:start()
|
||||||
|
print(t.running) // true
|
||||||
```
|
```
|
||||||
*/
|
*/
|
||||||
func (th *timersModule) loader(rtm *rt.Runtime) *rt.Table {
|
func (th *timersModule) loader(rtm *rt.Runtime) *rt.Table {
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
<h{{ (add .Level 1) }} id="{{ .Anchor | safeURL }}">
|
|
||||||
|
<h{{ (add .Level 1) }} id="{{ .Anchor | safeURL }}" class="heading">
|
||||||
{{ .Text | safeHTML }}
|
{{ .Text | safeHTML }}
|
||||||
|
<a href="#{{ .Anchor | safeURL }}" class='heading-link'>
|
||||||
|
<i class="fas fa-paperclip"></i>
|
||||||
|
</a>
|
||||||
</h{{ (add .Level 1) }}>
|
</h{{ (add .Level 1) }}>
|
||||||
|
|
||||||
{{ if eq .Text ""}}
|
{{ if eq .Text ""}}
|
||||||
<hr>
|
<hr>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<head>
|
<head>
|
||||||
{{ $title := print .Title " — " .Site.Title }}
|
{{ $title := print .Title " — " .Site.Title }}
|
||||||
{{ if .IsHome }}{{ $title = .Site.Title }}{{ end }}
|
{{ if .IsHome }}{{ $title = .Site.Title }}{{ end }}
|
||||||
<title>{{ $title }}</title>
|
<title>{{ $title }}</title>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no"/>
|
||||||
|
|
||||||
|
@ -23,4 +23,16 @@
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2" crossorigin="anonymous"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2" crossorigin="anonymous"></script>
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" integrity="sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" integrity="sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.heading > .heading-link {
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading:hover > .heading-link {
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1;
|
||||||
|
transition: all .1s ease-in;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
Loading…
Reference in New Issue