mirror of
https://github.com/zyedidia/micro.git
synced 2026-03-30 06:37:14 +09:00
Add support for plugin manager within micro
This commit is contained in:
@@ -55,6 +55,12 @@ func InitFlags() {
|
|||||||
fmt.Println(" \tRemove plugin(s)")
|
fmt.Println(" \tRemove plugin(s)")
|
||||||
fmt.Println("-plugin update [PLUGIN]...")
|
fmt.Println("-plugin update [PLUGIN]...")
|
||||||
fmt.Println(" \tUpdate plugin(s) (if no argument is given, updates all plugins)")
|
fmt.Println(" \tUpdate plugin(s) (if no argument is given, updates all plugins)")
|
||||||
|
fmt.Println("-plugin search [PLUGIN]...")
|
||||||
|
fmt.Println(" \tSearch for a plugin")
|
||||||
|
fmt.Println("-plugin list")
|
||||||
|
fmt.Println(" \tList installed plugins")
|
||||||
|
fmt.Println("-plugin available")
|
||||||
|
fmt.Println(" \tList available plugins")
|
||||||
|
|
||||||
fmt.Print("\nMicro's options can also be set via command line arguments for quick\nadjustments. For real configuration, please use the settings.json\nfile (see 'help options').\n\n")
|
fmt.Print("\nMicro's options can also be set via command line arguments for quick\nadjustments. For real configuration, please use the settings.json\nfile (see 'help options').\n\n")
|
||||||
fmt.Println("-option value")
|
fmt.Println("-option value")
|
||||||
@@ -107,76 +113,8 @@ func DoPluginFlags() {
|
|||||||
|
|
||||||
args := flag.Args()
|
args := flag.Args()
|
||||||
|
|
||||||
switch *flagPlugin {
|
config.PluginCommand(os.Stdout, *flagPlugin, args)
|
||||||
case "install":
|
|
||||||
installedVersions := config.GetInstalledVersions(false)
|
|
||||||
for _, plugin := range args {
|
|
||||||
pp := config.GetAllPluginPackages().Get(plugin)
|
|
||||||
if pp == nil {
|
|
||||||
fmt.Println("Unknown plugin \"" + plugin + "\"")
|
|
||||||
} else if err := pp.IsInstallable(); err != nil {
|
|
||||||
fmt.Println("Error installing ", plugin, ": ", err)
|
|
||||||
} else {
|
|
||||||
for _, installed := range installedVersions {
|
|
||||||
if pp.Name == installed.Pack().Name {
|
|
||||||
if pp.Versions[0].Version.Compare(installed.Version) == 1 {
|
|
||||||
fmt.Println(pp.Name, " is already installed but out-of-date: use 'plugin update ", pp.Name, "' to update")
|
|
||||||
} else {
|
|
||||||
fmt.Println(pp.Name, " is already installed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pp.Install()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case "remove":
|
|
||||||
removed := ""
|
|
||||||
for _, plugin := range args {
|
|
||||||
// check if the plugin exists.
|
|
||||||
for _, p := range config.Plugins {
|
|
||||||
if p.Name == plugin && p.Default {
|
|
||||||
fmt.Println("Default plugins cannot be removed, but can be disabled via settings.")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if p.Name == plugin {
|
|
||||||
config.UninstallPlugin(plugin)
|
|
||||||
removed += plugin + " "
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if removed != "" {
|
|
||||||
fmt.Println("Removed ", removed)
|
|
||||||
} else {
|
|
||||||
fmt.Println("No plugins removed")
|
|
||||||
}
|
|
||||||
case "update":
|
|
||||||
config.UpdatePlugins(args)
|
|
||||||
case "list":
|
|
||||||
plugins := config.GetInstalledVersions(false)
|
|
||||||
fmt.Println("The following plugins are currently installed:")
|
|
||||||
for _, p := range plugins {
|
|
||||||
fmt.Printf("%s (%s)\n", p.Pack().Name, p.Version)
|
|
||||||
}
|
|
||||||
case "search":
|
|
||||||
plugins := config.SearchPlugin(args)
|
|
||||||
fmt.Println(len(plugins), " plugins found")
|
|
||||||
for _, p := range plugins {
|
|
||||||
fmt.Println("----------------")
|
|
||||||
fmt.Println(p.String())
|
|
||||||
}
|
|
||||||
fmt.Println("----------------")
|
|
||||||
case "available":
|
|
||||||
packages := config.GetAllPluginPackages()
|
|
||||||
fmt.Println("Available Plugins:")
|
|
||||||
for _, pkg := range packages {
|
|
||||||
fmt.Println(pkg.Name)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
fmt.Println("Invalid plugin command")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -290,15 +228,15 @@ func main() {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
action.InitBindings()
|
err = config.LoadAllPlugins()
|
||||||
action.InitCommands()
|
|
||||||
|
|
||||||
err = config.InitColorscheme()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
screen.TermMessage(err)
|
screen.TermMessage(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = config.LoadAllPlugins()
|
action.InitBindings()
|
||||||
|
action.InitCommands()
|
||||||
|
|
||||||
|
err = config.InitColorscheme()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
screen.TermMessage(err)
|
screen.TermMessage(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,11 +120,20 @@ func CommandAction(cmd string) BufKeyAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var PluginCmds = []string{"list", "info", "version"}
|
var PluginCmds = []string{"install", "remove", "update", "available", "list", "search"}
|
||||||
|
|
||||||
// PluginCmd installs, removes, updates, lists, or searches for given plugins
|
// PluginCmd installs, removes, updates, lists, or searches for given plugins
|
||||||
func (h *BufPane) PluginCmd(args []string) {
|
func (h *BufPane) PluginCmd(args []string) {
|
||||||
InfoBar.Error("Plugin command disabled")
|
if len(args) < 1 {
|
||||||
|
InfoBar.Error("Not enough arguments")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.Buf.Type != buffer.BTLog {
|
||||||
|
OpenLogBuf(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
config.PluginCommand(buffer.LogBuf, args[0], args[1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// RetabCmd changes all spaces to tabs or all tabs to spaces
|
// RetabCmd changes all spaces to tabs or all tabs to spaces
|
||||||
|
|||||||
@@ -76,16 +76,24 @@ type SharedBuffer struct {
|
|||||||
// Whether or not suggestions can be autocompleted must be shared because
|
// Whether or not suggestions can be autocompleted must be shared because
|
||||||
// it changes based on how the buffer has changed
|
// it changes based on how the buffer has changed
|
||||||
HasSuggestions bool
|
HasSuggestions bool
|
||||||
|
|
||||||
|
// Modifications is the list of modified regions for syntax highlighting
|
||||||
|
Modifications []Loc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *SharedBuffer) insert(pos Loc, value []byte) {
|
func (b *SharedBuffer) insert(pos Loc, value []byte) {
|
||||||
b.isModified = true
|
b.isModified = true
|
||||||
b.HasSuggestions = false
|
b.HasSuggestions = false
|
||||||
b.LineArray.insert(pos, value)
|
b.LineArray.insert(pos, value)
|
||||||
|
|
||||||
|
// b.Modifications is cleared every screen redraw so it's
|
||||||
|
// ok to append duplicates
|
||||||
|
b.Modifications = append(b.Modifications, Loc{pos.Y, pos.Y + bytes.Count(value, []byte{'\n'})})
|
||||||
}
|
}
|
||||||
func (b *SharedBuffer) remove(start, end Loc) []byte {
|
func (b *SharedBuffer) remove(start, end Loc) []byte {
|
||||||
b.isModified = true
|
b.isModified = true
|
||||||
b.HasSuggestions = false
|
b.HasSuggestions = false
|
||||||
|
b.Modifications = append(b.Modifications, Loc{start.Y, start.Y})
|
||||||
return b.LineArray.remove(start, end)
|
return b.LineArray.remove(start, end)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,9 +123,7 @@ type Buffer struct {
|
|||||||
// This stores the highlighting rules and filetype detection info
|
// This stores the highlighting rules and filetype detection info
|
||||||
SyntaxDef *highlight.Def
|
SyntaxDef *highlight.Def
|
||||||
// The Highlighter struct actually performs the highlighting
|
// The Highlighter struct actually performs the highlighting
|
||||||
Highlighter *highlight.Highlighter
|
Highlighter *highlight.Highlighter
|
||||||
// Modifications is the list of modified regions for syntax highlighting
|
|
||||||
Modifications []Loc
|
|
||||||
HighlightLock sync.Mutex
|
HighlightLock sync.Mutex
|
||||||
|
|
||||||
// Hash of the original buffer -- empty if fastdirty is on
|
// Hash of the original buffer -- empty if fastdirty is on
|
||||||
@@ -333,10 +339,6 @@ func (b *Buffer) Insert(start Loc, text string) {
|
|||||||
b.EventHandler.active = b.curCursor
|
b.EventHandler.active = b.curCursor
|
||||||
b.EventHandler.Insert(start, text)
|
b.EventHandler.Insert(start, text)
|
||||||
|
|
||||||
// b.Modifications is cleared every screen redraw so it's
|
|
||||||
// ok to append duplicates
|
|
||||||
b.Modifications = append(b.Modifications, Loc{start.Y, start.Y + strings.Count(text, "\n")})
|
|
||||||
|
|
||||||
go b.Backup(true)
|
go b.Backup(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -348,8 +350,6 @@ func (b *Buffer) Remove(start, end Loc) {
|
|||||||
b.EventHandler.active = b.curCursor
|
b.EventHandler.active = b.curCursor
|
||||||
b.EventHandler.Remove(start, end)
|
b.EventHandler.Remove(start, end)
|
||||||
|
|
||||||
b.Modifications = append(b.Modifications, Loc{start.Y, start.Y})
|
|
||||||
|
|
||||||
go b.Backup(true)
|
go b.Backup(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -907,12 +907,12 @@ func ParseCursorLocation(cursorPositions []string) (Loc, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
startpos.Y, err = strconv.Atoi(cursorPositions[0])
|
startpos.Y, err = strconv.Atoi(cursorPositions[0])
|
||||||
startpos.Y -= 1
|
startpos.Y--
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if len(cursorPositions) > 1 {
|
if len(cursorPositions) > 1 {
|
||||||
startpos.X, err = strconv.Atoi(cursorPositions[1])
|
startpos.X, err = strconv.Atoi(cursorPositions[1])
|
||||||
if startpos.X > 0 {
|
if startpos.X > 0 {
|
||||||
startpos.X -= 1
|
startpos.X--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -925,6 +925,11 @@ func (b *Buffer) Line(i int) string {
|
|||||||
return string(b.LineBytes(i))
|
return string(b.LineBytes(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Buffer) Write(bytes []byte) (n int, err error) {
|
||||||
|
b.EventHandler.InsertBytes(b.End(), bytes)
|
||||||
|
return len(bytes), nil
|
||||||
|
}
|
||||||
|
|
||||||
// WriteLog writes a string to the log buffer
|
// WriteLog writes a string to the log buffer
|
||||||
func WriteLog(s string) {
|
func WriteLog(s string) {
|
||||||
LogBuf.EventHandler.Insert(LogBuf.End(), s)
|
LogBuf.EventHandler.Insert(LogBuf.End(), s)
|
||||||
|
|||||||
@@ -111,6 +111,11 @@ func (eh *EventHandler) ApplyDiff(new string) {
|
|||||||
// Insert creates an insert text event and executes it
|
// Insert creates an insert text event and executes it
|
||||||
func (eh *EventHandler) Insert(start Loc, textStr string) {
|
func (eh *EventHandler) Insert(start Loc, textStr string) {
|
||||||
text := []byte(textStr)
|
text := []byte(textStr)
|
||||||
|
eh.InsertBytes(start, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertBytes creates an insert text event and executes it
|
||||||
|
func (eh *EventHandler) InsertBytes(start Loc, text []byte) {
|
||||||
e := &TextEvent{
|
e := &TextEvent{
|
||||||
C: *eh.cursors[eh.active],
|
C: *eh.cursors[eh.active],
|
||||||
EventType: TextEventInsert,
|
EventType: TextEventInsert,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
ulua "github.com/zyedidia/micro/internal/lua"
|
ulua "github.com/zyedidia/micro/internal/lua"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ErrNoSuchFunction is returned when Call is executed on a function that does not exist
|
||||||
var ErrNoSuchFunction = errors.New("No such function exists")
|
var ErrNoSuchFunction = errors.New("No such function exists")
|
||||||
|
|
||||||
// LoadAllPlugins loads all detected plugins (in runtime/plugins and ConfigDir/plugins)
|
// LoadAllPlugins loads all detected plugins (in runtime/plugins and ConfigDir/plugins)
|
||||||
@@ -65,6 +66,7 @@ func RunPluginFnBool(fn string, args ...lua.LValue) (bool, error) {
|
|||||||
return retbool, reterr
|
return retbool, reterr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Plugin stores information about the source files/info for a plugin
|
||||||
type Plugin struct {
|
type Plugin struct {
|
||||||
DirName string // name of plugin folder
|
DirName string // name of plugin folder
|
||||||
Name string // name of plugin
|
Name string // name of plugin
|
||||||
@@ -74,6 +76,7 @@ type Plugin struct {
|
|||||||
Default bool // pre-installed plugin
|
Default bool // pre-installed plugin
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsEnabled returns if a plugin is enabled
|
||||||
func (p *Plugin) IsEnabled() bool {
|
func (p *Plugin) IsEnabled() bool {
|
||||||
if v, ok := GlobalSettings[p.Name]; ok {
|
if v, ok := GlobalSettings[p.Name]; ok {
|
||||||
return v.(bool) && p.Loaded
|
return v.(bool) && p.Loaded
|
||||||
@@ -81,13 +84,15 @@ func (p *Plugin) IsEnabled() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Plugins is a list of all detected plugins (enabled or disabled)
|
||||||
var Plugins []*Plugin
|
var Plugins []*Plugin
|
||||||
|
|
||||||
|
// Load creates an option for the plugin and runs all source files
|
||||||
func (p *Plugin) Load() error {
|
func (p *Plugin) Load() error {
|
||||||
|
if v, ok := GlobalSettings[p.Name]; ok && !v.(bool) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
for _, f := range p.Srcs {
|
for _, f := range p.Srcs {
|
||||||
if v, ok := GlobalSettings[p.Name]; ok && !v.(bool) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
dat, err := f.Data()
|
dat, err := f.Data()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -96,12 +101,13 @@ func (p *Plugin) Load() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
p.Loaded = true
|
|
||||||
RegisterGlobalOption(p.Name, true)
|
|
||||||
}
|
}
|
||||||
|
p.Loaded = true
|
||||||
|
RegisterGlobalOption(p.Name, true)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Call calls a given function in this plugin
|
||||||
func (p *Plugin) Call(fn string, args ...lua.LValue) (lua.LValue, error) {
|
func (p *Plugin) Call(fn string, args ...lua.LValue) (lua.LValue, error) {
|
||||||
plug := ulua.L.GetGlobal(p.Name)
|
plug := ulua.L.GetGlobal(p.Name)
|
||||||
if plug == lua.LNil {
|
if plug == lua.LNil {
|
||||||
@@ -125,7 +131,23 @@ func (p *Plugin) Call(fn string, args ...lua.LValue) (lua.LValue, error) {
|
|||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindPlugin returns the plugin with the given name
|
||||||
func FindPlugin(name string) *Plugin {
|
func FindPlugin(name string) *Plugin {
|
||||||
|
var pl *Plugin
|
||||||
|
for _, p := range Plugins {
|
||||||
|
if !p.IsEnabled() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if p.Name == name {
|
||||||
|
pl = p
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pl
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindAnyPlugin does not require the plugin to be enabled
|
||||||
|
func FindAnyPlugin(name string) *Plugin {
|
||||||
var pl *Plugin
|
var pl *Plugin
|
||||||
for _, p := range Plugins {
|
for _, p := range Plugins {
|
||||||
if p.Name == name {
|
if p.Name == name {
|
||||||
|
|||||||
@@ -118,17 +118,17 @@ func fetchAllSources(count int, fetcher func(i int) PluginPackages) PluginPackag
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fetch retrieves all available PluginPackages from the given channels
|
// Fetch retrieves all available PluginPackages from the given channels
|
||||||
func (pc PluginChannels) Fetch() PluginPackages {
|
func (pc PluginChannels) Fetch(out io.Writer) PluginPackages {
|
||||||
return fetchAllSources(len(pc), func(i int) PluginPackages {
|
return fetchAllSources(len(pc), func(i int) PluginPackages {
|
||||||
return pc[i].Fetch()
|
return pc[i].Fetch(out)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch retrieves all available PluginPackages from the given channel
|
// Fetch retrieves all available PluginPackages from the given channel
|
||||||
func (pc PluginChannel) Fetch() PluginPackages {
|
func (pc PluginChannel) Fetch(out io.Writer) PluginPackages {
|
||||||
resp, err := http.Get(string(pc))
|
resp, err := http.Get(string(pc))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to query plugin channel:\n", err)
|
fmt.Fprintln(out, "Failed to query plugin channel:\n", err)
|
||||||
return PluginPackages{}
|
return PluginPackages{}
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
@@ -136,19 +136,19 @@ func (pc PluginChannel) Fetch() PluginPackages {
|
|||||||
|
|
||||||
var repositories []PluginRepository
|
var repositories []PluginRepository
|
||||||
if err := decoder.Decode(&repositories); err != nil {
|
if err := decoder.Decode(&repositories); err != nil {
|
||||||
fmt.Println("Failed to decode channel data:\n", err)
|
fmt.Fprintln(out, "Failed to decode channel data:\n", err)
|
||||||
return PluginPackages{}
|
return PluginPackages{}
|
||||||
}
|
}
|
||||||
return fetchAllSources(len(repositories), func(i int) PluginPackages {
|
return fetchAllSources(len(repositories), func(i int) PluginPackages {
|
||||||
return repositories[i].Fetch()
|
return repositories[i].Fetch(out)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch retrieves all available PluginPackages from the given repository
|
// Fetch retrieves all available PluginPackages from the given repository
|
||||||
func (pr PluginRepository) Fetch() PluginPackages {
|
func (pr PluginRepository) Fetch(out io.Writer) PluginPackages {
|
||||||
resp, err := http.Get(string(pr))
|
resp, err := http.Get(string(pr))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to query plugin repository:\n", err)
|
fmt.Fprintln(out, "Failed to query plugin repository:\n", err)
|
||||||
return PluginPackages{}
|
return PluginPackages{}
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
@@ -156,7 +156,7 @@ func (pr PluginRepository) Fetch() PluginPackages {
|
|||||||
|
|
||||||
var plugins PluginPackages
|
var plugins PluginPackages
|
||||||
if err := decoder.Decode(&plugins); err != nil {
|
if err := decoder.Decode(&plugins); err != nil {
|
||||||
fmt.Println("Failed to decode repository data:\n", err)
|
fmt.Fprintln(out, "Failed to decode repository data:\n", err)
|
||||||
return PluginPackages{}
|
return PluginPackages{}
|
||||||
}
|
}
|
||||||
if len(plugins) > 0 {
|
if len(plugins) > 0 {
|
||||||
@@ -218,7 +218,7 @@ func (pp *PluginPackage) UnmarshalJSON(data []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetAllPluginPackages gets all PluginPackages which may be available.
|
// GetAllPluginPackages gets all PluginPackages which may be available.
|
||||||
func GetAllPluginPackages() PluginPackages {
|
func GetAllPluginPackages(out io.Writer) PluginPackages {
|
||||||
if allPluginPackages == nil {
|
if allPluginPackages == nil {
|
||||||
getOption := func(name string) []string {
|
getOption := func(name string) []string {
|
||||||
data := GetGlobalOption(name)
|
data := GetGlobalOption(name)
|
||||||
@@ -249,9 +249,9 @@ func GetAllPluginPackages() PluginPackages {
|
|||||||
}
|
}
|
||||||
allPluginPackages = fetchAllSources(len(repos)+1, func(i int) PluginPackages {
|
allPluginPackages = fetchAllSources(len(repos)+1, func(i int) PluginPackages {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
return channels.Fetch()
|
return channels.Fetch(out)
|
||||||
}
|
}
|
||||||
return repos[i-1].Fetch()
|
return repos[i-1].Fetch(out)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return allPluginPackages
|
return allPluginPackages
|
||||||
@@ -301,8 +301,8 @@ func (pp PluginPackage) Match(text string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IsInstallable returns true if the package can be installed.
|
// IsInstallable returns true if the package can be installed.
|
||||||
func (pp PluginPackage) IsInstallable() error {
|
func (pp PluginPackage) IsInstallable(out io.Writer) error {
|
||||||
_, err := GetAllPluginPackages().Resolve(GetInstalledVersions(true), PluginDependencies{
|
_, err := GetAllPluginPackages(out).Resolve(GetInstalledVersions(true), PluginDependencies{
|
||||||
&PluginDependency{
|
&PluginDependency{
|
||||||
Name: pp.Name,
|
Name: pp.Name,
|
||||||
Range: semver.Range(func(v semver.Version) bool { return true }),
|
Range: semver.Range(func(v semver.Version) bool { return true }),
|
||||||
@@ -312,18 +312,18 @@ func (pp PluginPackage) IsInstallable() error {
|
|||||||
|
|
||||||
// SearchPlugin retrieves a list of all PluginPackages which match the given search text and
|
// SearchPlugin retrieves a list of all PluginPackages which match the given search text and
|
||||||
// could be or are already installed
|
// could be or are already installed
|
||||||
func SearchPlugin(texts []string) (plugins PluginPackages) {
|
func SearchPlugin(out io.Writer, texts []string) (plugins PluginPackages) {
|
||||||
plugins = make(PluginPackages, 0)
|
plugins = make(PluginPackages, 0)
|
||||||
|
|
||||||
pluginLoop:
|
pluginLoop:
|
||||||
for _, pp := range GetAllPluginPackages() {
|
for _, pp := range GetAllPluginPackages(out) {
|
||||||
for _, text := range texts {
|
for _, text := range texts {
|
||||||
if !pp.Match(text) {
|
if !pp.Match(text) {
|
||||||
continue pluginLoop
|
continue pluginLoop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := pp.IsInstallable(); err == nil {
|
if err := pp.IsInstallable(out); err == nil {
|
||||||
plugins = append(plugins, pp)
|
plugins = append(plugins, pp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -363,6 +363,9 @@ func GetInstalledVersions(withCore bool) PluginVersions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, p := range Plugins {
|
for _, p := range Plugins {
|
||||||
|
if !p.IsEnabled() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
version := GetInstalledPluginVersion(p.Name)
|
version := GetInstalledPluginVersion(p.Name)
|
||||||
if pv := newStaticPluginVersion(p.Name, version); pv != nil {
|
if pv := newStaticPluginVersion(p.Name, version); pv != nil {
|
||||||
result = append(result, pv)
|
result = append(result, pv)
|
||||||
@@ -386,8 +389,8 @@ func GetInstalledPluginVersion(name string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DownloadAndInstall downloads and installs the given plugin and version
|
// DownloadAndInstall downloads and installs the given plugin and version
|
||||||
func (pv *PluginVersion) DownloadAndInstall() error {
|
func (pv *PluginVersion) DownloadAndInstall(out io.Writer) error {
|
||||||
fmt.Printf("Downloading %q (%s) from %q\n", pv.pack.Name, pv.Version, pv.Url)
|
fmt.Fprintf(out, "Downloading %q (%s) from %q\n", pv.pack.Name, pv.Version, pv.Url)
|
||||||
resp, err := http.Get(pv.Url)
|
resp, err := http.Get(pv.Url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -536,7 +539,7 @@ func (all PluginPackages) Resolve(selectedVersions PluginVersions, open PluginDe
|
|||||||
return selectedVersions, nil
|
return selectedVersions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pv PluginVersions) install() {
|
func (pv PluginVersions) install(out io.Writer) {
|
||||||
anyInstalled := false
|
anyInstalled := false
|
||||||
currentlyInstalled := GetInstalledVersions(true)
|
currentlyInstalled := GetInstalledVersions(true)
|
||||||
|
|
||||||
@@ -545,16 +548,16 @@ func (pv PluginVersions) install() {
|
|||||||
shouldInstall := true
|
shouldInstall := true
|
||||||
if pv := currentlyInstalled.find(sel.pack.Name); pv != nil {
|
if pv := currentlyInstalled.find(sel.pack.Name); pv != nil {
|
||||||
if pv.Version.NE(sel.Version) {
|
if pv.Version.NE(sel.Version) {
|
||||||
fmt.Println("Uninstalling", sel.pack.Name)
|
fmt.Fprintln(out, "Uninstalling", sel.pack.Name)
|
||||||
UninstallPlugin(sel.pack.Name)
|
UninstallPlugin(out, sel.pack.Name)
|
||||||
} else {
|
} else {
|
||||||
shouldInstall = false
|
shouldInstall = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if shouldInstall {
|
if shouldInstall {
|
||||||
if err := sel.DownloadAndInstall(); err != nil {
|
if err := sel.DownloadAndInstall(out); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Fprintln(out, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
anyInstalled = true
|
anyInstalled = true
|
||||||
@@ -562,49 +565,56 @@ func (pv PluginVersions) install() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if anyInstalled {
|
if anyInstalled {
|
||||||
fmt.Println("One or more plugins installed.")
|
fmt.Fprintln(out, "One or more plugins installed.")
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Nothing to install / update")
|
fmt.Fprintln(out, "Nothing to install / update")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// UninstallPlugin deletes the plugin folder of the given plugin
|
// UninstallPlugin deletes the plugin folder of the given plugin
|
||||||
func UninstallPlugin(name string) {
|
func UninstallPlugin(out io.Writer, name string) {
|
||||||
for _, p := range Plugins {
|
for _, p := range Plugins {
|
||||||
|
if !p.IsEnabled() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if p.Name == name {
|
if p.Name == name {
|
||||||
p.Loaded = false
|
p.Loaded = false
|
||||||
if err := os.RemoveAll(filepath.Join(ConfigDir, "plug", p.DirName)); err != nil {
|
if err := os.RemoveAll(filepath.Join(ConfigDir, "plug", p.DirName)); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Fprintln(out, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Install installs the plugin
|
// Install installs the plugin
|
||||||
func (pl PluginPackage) Install() {
|
func (pl PluginPackage) Install(out io.Writer) {
|
||||||
selected, err := GetAllPluginPackages().Resolve(GetInstalledVersions(true), PluginDependencies{
|
selected, err := GetAllPluginPackages(out).Resolve(GetInstalledVersions(true), PluginDependencies{
|
||||||
&PluginDependency{
|
&PluginDependency{
|
||||||
Name: pl.Name,
|
Name: pl.Name,
|
||||||
Range: semver.Range(func(v semver.Version) bool { return true }),
|
Range: semver.Range(func(v semver.Version) bool { return true }),
|
||||||
}})
|
}})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Fprintln(out, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
selected.install()
|
selected.install(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatePlugins updates the given plugins
|
// UpdatePlugins updates the given plugins
|
||||||
func UpdatePlugins(plugins []string) {
|
func UpdatePlugins(out io.Writer, plugins []string) {
|
||||||
// if no plugins are specified, update all installed plugins.
|
// if no plugins are specified, update all installed plugins.
|
||||||
if len(plugins) == 0 {
|
if len(plugins) == 0 {
|
||||||
for _, p := range Plugins {
|
for _, p := range Plugins {
|
||||||
|
if !p.IsEnabled() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
plugins = append(plugins, p.Name)
|
plugins = append(plugins, p.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Checking for plugin updates")
|
fmt.Fprintln(out, "Checking for plugin updates")
|
||||||
microVersion := PluginVersions{
|
microVersion := PluginVersions{
|
||||||
newStaticPluginVersion(CorePluginName, util.Version),
|
newStaticPluginVersion(CorePluginName, util.Version),
|
||||||
}
|
}
|
||||||
@@ -621,10 +631,82 @@ func UpdatePlugins(plugins []string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selected, err := GetAllPluginPackages().Resolve(microVersion, updates)
|
selected, err := GetAllPluginPackages(out).Resolve(microVersion, updates)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Fprintln(out, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
selected.install()
|
selected.install(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PluginCommand(out io.Writer, cmd string, args []string) {
|
||||||
|
switch cmd {
|
||||||
|
case "install":
|
||||||
|
installedVersions := GetInstalledVersions(false)
|
||||||
|
for _, plugin := range args {
|
||||||
|
pp := GetAllPluginPackages(out).Get(plugin)
|
||||||
|
if pp == nil {
|
||||||
|
fmt.Fprintln(out, "Unknown plugin \""+plugin+"\"")
|
||||||
|
} else if err := pp.IsInstallable(out); err != nil {
|
||||||
|
fmt.Fprintln(out, "Error installing ", plugin, ": ", err)
|
||||||
|
} else {
|
||||||
|
for _, installed := range installedVersions {
|
||||||
|
if pp.Name == installed.Pack().Name {
|
||||||
|
if pp.Versions[0].Version.Compare(installed.Version) == 1 {
|
||||||
|
fmt.Fprintln(out, pp.Name, " is already installed but out-of-date: use 'plugin update ", pp.Name, "' to update")
|
||||||
|
} else {
|
||||||
|
fmt.Fprintln(out, pp.Name, " is already installed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pp.Install(out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case "remove":
|
||||||
|
removed := ""
|
||||||
|
for _, plugin := range args {
|
||||||
|
// check if the plugin exists.
|
||||||
|
for _, p := range Plugins {
|
||||||
|
if p.Name == plugin && p.Default {
|
||||||
|
fmt.Fprintln(out, "Default plugins cannot be removed, but can be disabled via settings.")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if p.Name == plugin {
|
||||||
|
UninstallPlugin(out, plugin)
|
||||||
|
removed += plugin + " "
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if removed != "" {
|
||||||
|
fmt.Fprintln(out, "Removed ", removed)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintln(out, "No plugins removed")
|
||||||
|
}
|
||||||
|
case "update":
|
||||||
|
UpdatePlugins(out, args)
|
||||||
|
case "list":
|
||||||
|
plugins := GetInstalledVersions(false)
|
||||||
|
fmt.Fprintln(out, "The following plugins are currently installed:")
|
||||||
|
for _, p := range plugins {
|
||||||
|
fmt.Fprintf(out, "%s (%s)\n", p.Pack().Name, p.Version)
|
||||||
|
}
|
||||||
|
case "search":
|
||||||
|
plugins := SearchPlugin(out, args)
|
||||||
|
fmt.Fprintln(out, len(plugins), " plugins found")
|
||||||
|
for _, p := range plugins {
|
||||||
|
fmt.Fprintln(out, "----------------")
|
||||||
|
fmt.Fprintln(out, p.String())
|
||||||
|
}
|
||||||
|
fmt.Fprintln(out, "----------------")
|
||||||
|
case "available":
|
||||||
|
packages := GetAllPluginPackages(out)
|
||||||
|
fmt.Fprintln(out, "Available Plugins:")
|
||||||
|
for _, pkg := range packages {
|
||||||
|
fmt.Fprintln(out, pkg.Name)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
fmt.Fprintln(out, "Invalid plugin command")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user