Jumplist Database Program in Go
Tag: PROGRAM
Edit Created: 2019/10/24
Updated: 2019/10/24
Jumplist database
This program consists of two files, main.go, and kv.go, listed below.
It is used to manage the database of jump locations, and is intended to be called by a series of batch scripts
It’s currently done in a naive way, so as to preserve insertion order, and to keep from having to attach to something like SQLite. Even if the jumplist gets up to 100 elements, this code will remain quick, and it preserves order, and avoid a dependency on anything that Go doesn’t ship with.
You’ll want to drop these two files into a folder, run go build -o jumplist.exe
on them, and then take jumplist.exe and copy it to a directory on your path.
main.go
package main
import (
"fmt"
"os"
"path/filepath"
"strings"
)
func main() {
if len(os.Args) > 1 {
dispatch()
} else {
fmt.Println("Not enough args!")
}
}
func dispatch() {
cmd := os.Args[1]
kv := OpenStore()
switch cmd {
case "-add":
if len(os.Args) < 3 {
fmt.Println("Need at least one argument to the -add flag")
return
}
wd, err := os.Getwd()
die(err)
kv.Add(entry{Key: os.Args[2], Value: wd})
case "-rm":
if len(os.Args) < 3 {
fmt.Println("Need at least one argument to the -rm flag")
return
}
kv.Remove(os.Args[2])
case "-ls":
ListDirs(kv)
default:
// If it's not one of the above commands, emit the path for the wrapping script to use for jumping.
if target, found := kv.Get(os.Args[1]); found {
fmt.Println(target.Value)
} else {
fmt.Println(".")
}
}
f, err := os.Create(dbpath())
defer f.Close()
die(err)
die(SaveKVFile(f, kv))
}
func die(e error) {
if e != nil {
panic(e)
}
}
func ListDirs(kv store) {
maxKeyLen := 0
for _, entry := range kv {
if len(entry.Key) > maxKeyLen {
maxKeyLen = len(entry.Key)
}
}
for _, entry := range kv {
fmt.Print(RightPad2Len(entry.Key, " ", maxKeyLen))
fmt.Print(" -> ")
fmt.Println(entry.Value)
}
}
// RightPad2Len https://github.com/DaddyOh/golang-samples/blob/master/pad.go
func RightPad2Len(s string, padStr string, overallLen int) string {
var padCountInt = 1 + ((overallLen - len(padStr)) / len(padStr))
var retStr = s + strings.Repeat(padStr, padCountInt)
return retStr[:overallLen]
}
func dbpath() string {
home, err := os.UserHomeDir()
die(err)
return filepath.Join(home, ".jumpdb")
}
func OpenStore() store {
kv, err := LoadKVFile(dbpath())
die(err)
return kv
}
kv.go
package main
import (
"bytes"
"fmt"
"io"
"io/ioutil"
)
type store []*entry
type entry struct {
Key string
Value string
}
var ASCII_RECORD_SEPERATOR = []byte{byte(30)}
var ASCII_UNIT_SEPERATOR = []byte{byte(31)}
func (me *store) Get(key string) (*entry, bool) {
for _, e := range *me {
if e.Key == key {
return e, true
}
}
return nil, false
}
func (me *store) Remove(key string) {
for i, e := range *me {
if e.Key == key {
// Delete the lement from the slice?
copy((*me)[i:], (*me)[i+1:])
*me = (*me)[:len(*me)-1]
break
}
}
}
func (me *store) Add(e entry) {
temp := append(*me, &e)
*me = temp
}
func LoadKVFile(path string) (store, error) {
data, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
if len(data) == 0 {
return make(store, 0), nil
}
rows := bytes.Split(data, ASCII_RECORD_SEPERATOR)
kvStore := make(store, 0)
for _, row := range rows {
if len(row) == 0 {
continue
}
cols := bytes.Split(row, ASCII_UNIT_SEPERATOR)
if len(cols) != 2 {
return nil, fmt.Errorf("Invalid row: %v", row)
}
kvStore = append(kvStore, &entry{
Key: string(cols[0]),
Value: string(cols[1]),
})
}
return kvStore, nil
}
func SaveKVFile(result io.Writer, entries store) error {
for _, row := range entries {
io.WriteString(result, row.Key)
result.Write(ASCII_UNIT_SEPERATOR)
io.WriteString(result, row.Value)
result.Write(ASCII_RECORD_SEPERATOR)
}
return nil
}