Skip to content

Commit

Permalink
feat: extension system
Browse files Browse the repository at this point in the history
  • Loading branch information
tsukinoko-kun committed Sep 24, 2024
1 parent 2902f99 commit c7ebfb9
Show file tree
Hide file tree
Showing 7 changed files with 221 additions and 175 deletions.
172 changes: 0 additions & 172 deletions internal/shell/context.go

This file was deleted.

25 changes: 25 additions & 0 deletions internal/shell/extensions/dotnet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package extensions

import (
"os"
"smash/internal/color"
"strings"
)

type dotnet struct {
}

const dotnetPromptDisplay = color.FgMagenta + "\U000F0AAE"

func (_ *dotnet) PromptDisplay() string {
return dotnetPromptDisplay
}

func (_ *dotnet) FileMatch(f os.DirEntry, _ string) bool {
n := f.Name()
return strings.HasSuffix(n, ".sln") || strings.HasSuffix(n, ".csproj") || strings.HasSuffix(n, ".fsproj")
}

func init() {
register(&dotnet{})
}
74 changes: 74 additions & 0 deletions internal/shell/extensions/extensions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package extensions

import (
"errors"
"os"
"path/filepath"
"strings"
)

var extensionRegister []*extensionWrapper

type (
Extension interface {
PromptDisplay() string
FileMatch(f os.DirEntry, p string) bool
}
extensionWrapper struct {
extension Extension
active bool
}
)

func register(e Extension) {
extensionRegister = append(extensionRegister, &extensionWrapper{extension: e, active: true})
}

func priorityRegister(e Extension) {
extensionRegister = append([]*extensionWrapper{{extension: e, active: true}}, extensionRegister...)
}

func SetContext(root string) error {
// deactivate all extensions
for _, ew := range extensionRegister {
ew.active = false
}

// activate extensions that match the current context
for {
entries, err := os.ReadDir(root)
if err != nil {
return errors.Join(errors.New("failed to read directory"), err)
}
for _, f := range entries {
p := filepath.Join(root, f.Name())
for _, ew := range extensionRegister {
if ew.active {
continue
}
if ew.extension.FileMatch(f, p) {
ew.active = true
continue
}
}
}

nextRoot := filepath.Dir(root)
if nextRoot == root {
break
}
root = nextRoot
}
return nil
}

func PromptDisplay() string {
sb := strings.Builder{}
for _, ew := range extensionRegister {
if ew.active {
sb.WriteString(ew.extension.PromptDisplay())
sb.WriteString(" ")
}
}
return sb.String()
}
28 changes: 28 additions & 0 deletions internal/shell/extensions/git.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package extensions

import (
"os"
"os/exec"
"smash/internal/color"
"strings"
)

type git struct {
}

func (_ *git) PromptDisplay() string {
cmd := exec.Command("git", "branch", "--show-current")
if out, err := cmd.Output(); err == nil {
return color.FgGreen + "\U000F02A2 " + strings.TrimSpace(string(out))
} else {
return color.FgGreen + "\U000F02A2"
}
}

func (_ *git) FileMatch(f os.DirEntry, _ string) bool {
return f.Name() == ".git"
}

func init() {
priorityRegister(&git{})
}
45 changes: 45 additions & 0 deletions internal/shell/extensions/golang.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package extensions

import (
"bufio"
"os"
"smash/internal/color"
"strings"
)

type golang struct {
mod string
}

const goPromptDisplay = color.FgBlue + "\uE627"

func (g *golang) PromptDisplay() string {
f, err := os.Open(g.mod)
if err != nil {
return goPromptDisplay
}
defer f.Close()

scanner := bufio.NewScanner(f)
scanner.Split(bufio.ScanLines)

for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "go ") {
return goPromptDisplay + " " + strings.TrimSpace(line[3:])
}
}
return goPromptDisplay
}

func (g *golang) FileMatch(f os.DirEntry, p string) bool {
if f.Name() == "go.mod" {
g.mod = p
return true
}
return false
}

func init() {
register(&golang{})
}
46 changes: 46 additions & 0 deletions internal/shell/extensions/ruby.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package extensions

import (
"bufio"
"fmt"
"os"
"smash/internal/color"
)

type ruby struct {
gemfile string
}

const rubyPromptDisplay = color.FgRed + "\uE739"

func (ru *ruby) PromptDisplay() string {
f, err := os.Open(ru.gemfile)
if err != nil {
return rubyPromptDisplay
}
defer f.Close()

scanner := bufio.NewScanner(f)
scanner.Split(bufio.ScanLines)

for scanner.Scan() {
line := scanner.Text()
var version string
if _, err := fmt.Sscanf(line, `ruby "%s"`, &version); err == nil {
return rubyPromptDisplay + " " + version
}
}
return rubyPromptDisplay
}

func (ru *ruby) FileMatch(f os.DirEntry, p string) bool {
if f.Name() == "Gemfile" {
ru.gemfile = p
return true
}
return false
}

func init() {
register(&ruby{})
}
Loading

0 comments on commit c7ebfb9

Please sign in to comment.