Skip to content

Commit

Permalink
Add a config parser and init a config validor for future features
Browse files Browse the repository at this point in the history
  • Loading branch information
alexandrebodin committed Jul 6, 2018
1 parent e031ccf commit df7625e
Show file tree
Hide file tree
Showing 8 changed files with 261 additions and 133 deletions.
28 changes: 0 additions & 28 deletions config.go

This file was deleted.

114 changes: 114 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package config

import (
"errors"
"fmt"
"io"

"github.com/BurntSushi/toml"
)

// Pane contains a pane configuration
type Pane struct {
Dir string
Zoom bool
Split string
Scripts []string
}

// Window contains a window configuration
type Window struct {
Name string
Dir string
Layout string
Sync bool
Scripts []string
Panes []Pane
PaneScripts []string `toml:"pane-scripts"`
}

// Session contains a tmux session configuration
type Session struct {
Name string
Dir string
ClearPanes bool `toml:"clear-panes"`
Windows []Window
SelectWindow string `toml:"select-window"`
SelectPane int `toml:"select-pane"`
WindowScripts []string `toml:"window-scripts"`
}

var (
validLayouts = []string{
"even-horizontal",
"even-vertical",
"main-horizontal",
"main-vertical",
"tiled",
}
)

func checkValid(conf Session) error {
// check at least one window
if len(conf.Windows) == 0 {
return errors.New("you must declare at least on window (0 provided)")
}

// check select-window and select-pane exist
if conf.SelectWindow != "" {
var win Window
found := false
for _, w := range conf.Windows {
if w.Name == conf.SelectWindow {
win = w
found = true
break
}
}

if !found {
return fmt.Errorf("selected window %s doesn't exist", conf.SelectWindow)
}

if conf.SelectPane != 0 {
if len(win.Panes) < conf.SelectPane {
return fmt.Errorf("selected pane %d doesn't exist", conf.SelectPane)
}
}
}

for _, w := range conf.Windows {
if w.Layout != "" {
found := false
for _, l := range validLayouts {
if l == w.Layout {
found = true
}
}

if !found {
return fmt.Errorf("invalid layout '%s' in window '%s'", w.Layout, w.Name)
}
}
}

// check only on zoom in a window

return nil
}

// Parse return a sessionConfig from a io.Reader
func Parse(reader io.ReadCloser) (Session, error) {
defer reader.Close()

var conf Session
if _, err := toml.DecodeReader(reader, &conf); err != nil {
return conf, fmt.Errorf("parsing configuration: %v", err)
}

if err := checkValid(conf); err != nil {
return conf, err
}

return conf, nil
}
23 changes: 14 additions & 9 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ import (
"log"
"os"

"github.com/BurntSushi/toml"
"github.com/alecthomas/kingpin"
"github.com/alexandrebodin/go-findup"
"github.com/alexandrebodin/tmuxctl/config"
"github.com/alexandrebodin/tmuxctl/tmux"
)

var (
version = "development"
start = kingpin.Command("start", "start a tmux instance").Default()
config = start.Arg("config", "Tmux config file").Default(".tmuxctlrc").String()
version = "development"
start = kingpin.Command("start", "start a tmux instance").Default()
configPath = start.Arg("config", "Tmux config file").Default(".tmuxctlrc").String()
)

func main() {
Expand All @@ -23,16 +23,21 @@ func main() {
kingpin.CommandLine.VersionFlag.Short('v')
kingpin.Parse()

fmt.Printf("Start tmux with config file: %v\n", *config)
fmt.Printf("Start tmux with config file: %v\n", *configPath)

filePath, err := findup.Find(*config)
filePath, err := findup.Find(*configPath)
if err != nil {
log.Fatalf("Error locating config file %v\n", err)
}

var conf sessionConfig
if _, err := toml.DecodeFile(filePath, &conf); err != nil {
log.Fatalf("Error loading configuration %v\n", err)
file, err := os.Open(filePath)
if err != nil {
log.Fatalf("Error openning config file %v\n", err)
}

conf, err := config.Parse(file)
if err != nil {
log.Fatalf("Error parsing %s: %v\n", filePath, err)
}

runningSessions, err := tmux.ListSessions()
Expand Down
3 changes: 2 additions & 1 deletion pane.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"strconv"

"github.com/alexandrebodin/tmuxctl/config"
"github.com/alexandrebodin/tmuxctl/tmux"
)

Expand All @@ -15,7 +16,7 @@ type pane struct {
Target string
}

func newPane(win *window, config paneConfig, index int) *pane {
func newPane(win *window, config config.Pane, index int) *pane {
normalizedIndex := strconv.Itoa(index + win.Sess.TmuxOptions.PaneBaseIndex)
pane := &pane{
Window: win,
Expand Down
3 changes: 2 additions & 1 deletion session.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os/exec"
"syscall"

"github.com/alexandrebodin/tmuxctl/config"
"github.com/alexandrebodin/tmuxctl/tmux"
)

Expand All @@ -19,7 +20,7 @@ type session struct {
WindowScripts []string
}

func newSession(config sessionConfig, options *tmux.Options) *session {
func newSession(config config.Session, options *tmux.Options) *session {
sess := &session{
Name: config.Name,
Dir: lookupDir(config.Dir),
Expand Down
101 changes: 8 additions & 93 deletions tmux/commands.go
Original file line number Diff line number Diff line change
@@ -1,116 +1,31 @@
package tmux

import (
"bytes"
"fmt"
"os/exec"
"strconv"
"strings"
var (
// DefaultRunner is the default tmux command runner
DefaultRunner = &Runner{}
)

// Result is a commadn result
type Result struct {
Stdout string
Stderr string
}

// Exec runs a tmux command
func Exec(args ...string) (Result, error) {
var stdin bytes.Buffer
var stderr bytes.Buffer
var stdout bytes.Buffer

cmd := exec.Command("tmux", args...)
cmd.Stdin = &stdin
cmd.Stdout = &stdout
cmd.Stderr = &stderr

err := cmd.Run()
if err != nil {
return Result{}, fmt.Errorf("Error running command \"tmux %v\", %s", args, stderr.String())
}

return Result{stdout.String(), stderr.String()}, nil
return DefaultRunner.Exec(args...)
}

// SendKeys sends keys to tmux (e.g to run a command)
func SendKeys(target, keys string) error {
_, err := Exec("send-keys", "-R", "-t", target, keys, "C-m")
return err
return DefaultRunner.SendKeys(target, keys)
}

// SendRawKeys sends keys to tmux (e.g to run a command)
func SendRawKeys(target, keys string) error {
_, err := Exec("send-keys", "-R", "-t", target, keys)
return err
return DefaultRunner.SendRawKeys(target, keys)
}

// SessionInfo infos about a running tmux session
type SessionInfo struct{}

// ListSessions returns the list of sessions currently running
func ListSessions() (map[string]SessionInfo, error) {
sessionMap := make(map[string]SessionInfo)

res, err := Exec("ls")
if err != nil {
if strings.Contains(err.Error(), "no server running on") {
return sessionMap, nil
}
return sessionMap, fmt.Errorf("error listing sessions %v", err)
}

splits := strings.Split(res.Stdout, "\n")
for _, sess := range splits {
sessSplits := strings.Split(sess, ":")
if len(sessSplits) > 1 {
sessionMap[sessSplits[0]] = SessionInfo{}
}
}

return sessionMap, nil
}

// Options tmux options
type Options struct {
BaseIndex int
PaneBaseIndex int
return DefaultRunner.ListSessions()
}

// GetOptions get tmux options
func GetOptions() (*Options, error) {
options := &Options{
BaseIndex: 0,
PaneBaseIndex: 0,
}

var stderr bytes.Buffer
var stdout bytes.Buffer
cmd := exec.Command("sh", "-c", "tmux start-server\\; show-options -g\\; show-window-options -g")
cmd.Stdout = &stdout

err := cmd.Run()
if err != nil {
return options, fmt.Errorf("Error getting tmux options %v, %s", err, stderr.String())
}

optionsString := strings.Split(stdout.String(), "\n")
for _, option := range optionsString {
optionSplits := strings.Split(option, " ")
if len(optionSplits) == 2 {
name := optionSplits[0]
if name == "base-index" {
if v, err := strconv.Atoi(optionSplits[1]); err == nil {
options.BaseIndex = v
}
} else if name == "pane-base-index" {
if v, err := strconv.Atoi(optionSplits[1]); err == nil {
options.PaneBaseIndex = v
}

}
}
}

return options, nil
return DefaultRunner.GetOptions()
}

0 comments on commit df7625e

Please sign in to comment.