Skip to content

Commit

Permalink
New completions package with embedded scripts in binary
Browse files Browse the repository at this point in the history
Our completion scripts can be embedded as global strings.

New zsh-completion and bash-completion subcommands print these embedded
strings to stdout. Users can source them from their startup scripts:

    source <(dstask zsh-completion)

Add symlinks at original completion script locations
  • Loading branch information
dontlaugh committed Jan 29, 2022
1 parent c7007e4 commit a8e5261
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 68 deletions.
25 changes: 0 additions & 25 deletions .dstask-bash-completions.sh

This file was deleted.

1 change: 1 addition & 0 deletions .dstask-bash-completions.sh
9 changes: 0 additions & 9 deletions .dstask-zsh-completions.sh

This file was deleted.

1 change: 1 addition & 0 deletions .dstask-zsh-completions.sh
9 changes: 8 additions & 1 deletion cmd/dstask/main.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package main

import (
"fmt"
"os"
"strings"

"github.com/naggie/dstask"
"github.com/naggie/dstask/completions"
)

func main() {
Expand Down Expand Up @@ -161,8 +163,13 @@ func main() {
dstask.CommandVersion()

case dstask.CMD_COMPLETIONS:
dstask.Completions(conf, os.Args, ctx)
completions.Completions(conf, os.Args, ctx)

case dstask.CMD_PRINT_BASH_COMPLETION:
fmt.Printf(completions.Bash)

case dstask.CMD_PRINT_ZSH_COMPLETION:
fmt.Printf(completions.Zsh)
default:
panic("this should never happen?")
}
Expand Down
25 changes: 25 additions & 0 deletions completions/bash.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# wire bash completions to dstask completion engine. Some of the workarounds for
# idiosyncrasies around separation with colons taken from /etc/bash_completion

_dstask() {
# reconstruct COMP_WORDS to re-join separations caused by colon (which is a default separator)
# yes, this method ends up splitting by spaces, but that's not a problem for the dstask parser
# see http://tiswww.case.edu/php/chet/bash/FAQ
original_args=( $(echo "${COMP_WORDS[@]}" | sed 's/ : /:/g' | sed 's/ :$/:/g') )

# hand to dstask as canonical args
COMPREPLY=( $(dstask _completions "${original_args[@]}") )

# convert dstask's suggestions to remove prefix before colon so complete can understand it
local last_arg="${original_args[-1]}"
local colon_word=${last_arg%"${last_arg##*:}"}
local i=${#COMPREPLY[*]}
while [[ $((--i)) -ge 0 ]]; do
COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
done
}

complete -F _dstask dstask
complete -F _dstask task
#complete -F _dstask n
#complete -F _dstask t
67 changes: 34 additions & 33 deletions completions.go → completions/completions.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package dstask
package completions

import (
"fmt"
"github.com/naggie/dstask"
"log"
"strconv"
"strings"
)

// Completions ...
func Completions(conf Config, args []string, ctx Query) {
func Completions(conf dstask.Config, args []string, ctx dstask.Query) {
// given the entire user's command line arguments as the arguments for
// this cmd, suggest possible candidates for the last arg.
// see the relevant shell completion bindings in this repository for
Expand All @@ -26,7 +27,7 @@ func Completions(conf Config, args []string, ctx Query) {

// args are dstask _completions <user command line>
// parse command line as normal to set rules
query := ParseQuery(originalArgs...)
query := dstask.ParseQuery(originalArgs...)

// No command and OK to specify command (to run or help)
// Note that techically we should only specify commands as available
Expand All @@ -41,35 +42,35 @@ func Completions(conf Config, args []string, ctx Query) {
query.Priority == "" &&
query.Template == 0 &&
!query.IgnoreContext &&
(query.Cmd == CMD_HELP || query.Cmd == "") {
for _, cmd := range ALL_CMDS {
(query.Cmd == dstask.CMD_HELP || query.Cmd == "") {
for _, cmd := range dstask.ALL_CMDS {
if !strings.HasPrefix(cmd, "_") {
completions = append(completions, cmd)
}
}
}

if StrSliceContains([]string{
if dstask.StrSliceContains([]string{
"",
CMD_NEXT,
CMD_ADD,
CMD_REMOVE,
CMD_LOG,
CMD_START,
CMD_STOP,
CMD_DONE,
CMD_RESOLVE,
CMD_CONTEXT,
CMD_MODIFY,
CMD_SHOW_NEXT,
CMD_SHOW_PROJECTS,
CMD_SHOW_ACTIVE,
CMD_SHOW_PAUSED,
CMD_SHOW_OPEN,
CMD_SHOW_RESOLVED,
CMD_SHOW_TEMPLATES,
dstask.CMD_NEXT,
dstask.CMD_ADD,
dstask.CMD_REMOVE,
dstask.CMD_LOG,
dstask.CMD_START,
dstask.CMD_STOP,
dstask.CMD_DONE,
dstask.CMD_RESOLVE,
dstask.CMD_CONTEXT,
dstask.CMD_MODIFY,
dstask.CMD_SHOW_NEXT,
dstask.CMD_SHOW_PROJECTS,
dstask.CMD_SHOW_ACTIVE,
dstask.CMD_SHOW_PAUSED,
dstask.CMD_SHOW_OPEN,
dstask.CMD_SHOW_RESOLVED,
dstask.CMD_SHOW_TEMPLATES,
}, query.Cmd) {
ts, err := LoadTaskSet(conf.Repo, conf.IDsFile, false)
ts, err := dstask.LoadTaskSet(conf.Repo, conf.IDsFile, false)
if err != nil {
log.Printf("completions error: %v\n", err)
return
Expand All @@ -79,25 +80,25 @@ func Completions(conf Config, args []string, ctx Query) {
// trying to change context, context ignore is on, or modify
// command is being completed
if !query.IgnoreContext &&
query.Cmd != CMD_CONTEXT &&
query.Cmd != CMD_MODIFY {
query.Cmd != dstask.CMD_CONTEXT &&
query.Cmd != dstask.CMD_MODIFY {
ts.Filter(ctx)
}

// templates
if query.Cmd == CMD_ADD {
if query.Cmd == dstask.CMD_ADD {
for _, task := range ts.Tasks() {
if task.Status == STATUS_TEMPLATE {
if task.Status == dstask.STATUS_TEMPLATE {
completions = append(completions, "template:"+strconv.Itoa(task.ID))
}
}
}

// priorities
completions = append(completions, PRIORITY_CRITICAL)
completions = append(completions, PRIORITY_HIGH)
completions = append(completions, PRIORITY_NORMAL)
completions = append(completions, PRIORITY_LOW)
completions = append(completions, dstask.PRIORITY_CRITICAL)
completions = append(completions, dstask.PRIORITY_HIGH)
completions = append(completions, dstask.PRIORITY_NORMAL)
completions = append(completions, dstask.PRIORITY_LOW)

// projects
for _, project := range ts.GetProjects() {
Expand All @@ -117,7 +118,7 @@ func Completions(conf Config, args []string, ctx Query) {
}

for _, completion := range completions {
if strings.HasPrefix(completion, prefix) && !StrSliceContains(originalArgs, completion) {
if strings.HasPrefix(completion, prefix) && !dstask.StrSliceContains(originalArgs, completion) {
fmt.Println(completion)
}
}
Expand Down
9 changes: 9 additions & 0 deletions completions/embed.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package completions

import _ "embed"

//go:embed zsh.sh
var Zsh string

//go:embed bash.sh
var Bash string
9 changes: 9 additions & 0 deletions completions/zsh.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#compdef dstask
#autoload


_dstask() {
compadd -- $(dstask _completions "${words[@]}")
}

compdef _dstask dstask
5 changes: 5 additions & 0 deletions const.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ const (
CMD_HELP = "help"
CMD_VERSION = "version"

CMD_PRINT_ZSH_COMPLETION = "zsh-completion"
CMD_PRINT_BASH_COMPLETION = "bash-completion"

// filter: P1 P2 etc
PRIORITY_CRITICAL = "P0"
PRIORITY_HIGH = "P1"
Expand Down Expand Up @@ -167,6 +170,8 @@ var ALL_CMDS = []string{
CMD_SHOW_TEMPLATES,
CMD_SHOW_UNORGANISED,
CMD_COMPLETIONS,
CMD_PRINT_BASH_COMPLETION,
CMD_PRINT_ZSH_COMPLETION,
CMD_HELP,
CMD_VERSION,
}

0 comments on commit a8e5261

Please sign in to comment.