From eb98658c40e76852f524c894444f28bd71356c11 Mon Sep 17 00:00:00 2001 From: Oleg Utkin Date: Tue, 5 Jul 2022 15:25:57 -0700 Subject: [PATCH] POC working, migrate to rendering prompt in pure go --- cmd/goprompt/main.go | 110 ++++++++++++++++++++++++++-------- zsh/prompt_asynczle_setup.zsh | 63 +++++++++++++++---- 2 files changed, 138 insertions(+), 35 deletions(-) diff --git a/cmd/goprompt/main.go b/cmd/goprompt/main.go index ff28275..704628d 100644 --- a/cmd/goprompt/main.go +++ b/cmd/goprompt/main.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "github.com/spf13/cobra" + "io" "os" "strings" "sync" @@ -18,18 +19,56 @@ var ( cmd = &cobra.Command{ Use: "goprompt", } - flgCmdStatus = cmd.PersistentFlags().Int( + + cmdQuery = &cobra.Command{ + Use: "query", + Short: "start the query that pulls data for the prompt", + } + flgQCmdStatus = cmdQuery.PersistentFlags().Int( "cmd-status", 0, "cmd status of previous command", ) - flgPreexecTS = cmd.PersistentFlags().Int( + flgQPreexecTS = cmdQuery.PersistentFlags().Int( "preexec-ts", 0, "pre-execution timestamp to gauge how log execution took", ) + + cmdRender = &cobra.Command{ + Use: "render", + Short: "render the prompt based on the results of query", + } ) func init() { - cmd.RunE = cmdExec + cmdQuery.RunE = cmdQueryRun + cmd.AddCommand(cmdQuery) + + cmdRender.RunE = cmdRenderRun + cmd.AddCommand(cmdRender) +} + +func cmdRenderRun(cmd *cobra.Command, args []string) error { + if _, err := os.Stdin.Stat(); err != nil { + fmt.Printf("%#v", err) + } + + out, err := io.ReadAll(os.Stdin) + if err != nil { + panic(err) + } + + lines := strings.Split(string(out), "\n") + vals := make(map[string]string) + for _, line := range lines { + key, value, ok := strings.Cut(line, "\t") + if ok { + vals[key] = value + } + } + + fmt.Printf("%#v\n", vals) + fmt.Printf(">") + return nil } // PROMPT PARTS: @@ -40,9 +79,9 @@ func init() { // (vsc-information) // (timestamp) -func cmdExec(cmd *cobra.Command, args []string) error { - if *flgCmdStatus != 0 { - printPart("st", fmt.Sprintf("%#v", *flgCmdStatus)) +func cmdQueryRun(cmd *cobra.Command, args []string) error { + if *flgQCmdStatus != 0 { + printPart("st", fmt.Sprintf("%#v", *flgQCmdStatus)) } wg := new(WaitGroupDispatcher) @@ -61,8 +100,8 @@ func cmdExec(cmd *cobra.Command, args []string) error { nowTS := time.Now() printPart("ts", nowTS.Format("15:04:05 01/02/06")) - if *flgPreexecTS != 0 { - cmdTS := time.Unix(int64(*flgPreexecTS), 0) + if *flgQPreexecTS != 0 { + cmdTS := time.Unix(int64(*flgQPreexecTS), 0) diff := nowTS.Sub(cmdTS) printPart("ds", diff.Round(time.Second)) @@ -89,7 +128,19 @@ func cmdExec(cmd *cobra.Command, args []string) error { cwg.Dispatch(func() { if branch, err := stringExec("git", "branch", "--show-current"); err == nil { - printPart("vcs_br", trim(string(branch))) + branch = trim(branch) + if len(branch) > 0 { + printPart("vcs_br", trim(branch)) + return + } + } + + if branch, err := stringExec("git", "name-rev", "--name-only", "HEAD"); err == nil { + branch = trim(branch) + if len(branch) > 0 { + printPart("vcs_br", trim(branch)) + return + } } }) @@ -103,17 +154,40 @@ func cmdExec(cmd *cobra.Command, args []string) error { } } }) + + cwg.Dispatch(func() { + if status, err := stringExec("git", "rev-list", "--left-right", "--count", "HEAD...@{u}"); err == nil { + parts := strings.SplitN(status, "\t", 2) + if len(parts) < 2 { + parts = []string{"0", "0"} + } + + printPart("vcs_log_ahead", parts[0]) + printPart("vcs_log_behind", parts[1]) + } + }) }) wg.Dispatch(func() { + var err error + cwg := new(WaitGroupDispatcher) defer cwg.Wait() - var stgPatchTop string - var err error + var stgSeriesLen string + if stgSeriesLen, err = stringExec("stg", "series", "-c"); err == nil { + printPart("stg", "1") + printPart("stg_qlen", stgSeriesLen) + } + cwg.Dispatch(func() { + if stgSeriesPos, err := stringExec("stg", "series", "-cA"); err == nil { + printPart("stg_qpos", stgSeriesPos) + } + }) + + var stgPatchTop string if stgPatchTop, err = stringExec("stg", "top"); err == nil { - printPart("stg", "1") printPart("stg_top", stgPatchTop) } else { return @@ -129,18 +203,6 @@ func cmdExec(cmd *cobra.Command, args []string) error { printPart("stg_dirty", 0) } }) - - cwg.Dispatch(func() { - if stgPatchLen, err := stringExec("stg", "series", "-c"); err == nil { - printPart("stg_qlen", stgPatchLen) - } - }) - - cwg.Dispatch(func() { - if stgPatchPos, err := stringExec("stg", "series", "-cA"); err == nil { - printPart("stg_qpos", stgPatchPos) - } - }) }) return nil diff --git a/zsh/prompt_asynczle_setup.zsh b/zsh/prompt_asynczle_setup.zsh index efe4d0f..d6ad04c 100644 --- a/zsh/prompt_asynczle_setup.zsh +++ b/zsh/prompt_asynczle_setup.zsh @@ -40,9 +40,12 @@ typeset -g C_PROMPT_NEWLINE=$'\n%{\r%}' typeset -g G_LAST_STATUS=0 typeset -g G_PREEXEC_TS=0 +typeset -g G_ASYNC_DONE=0 typeset -gA G_PROMPT_PARTS=() +typeset -g G_LAST_PROMPT="" + #------------------------------------------------------------------------------- __async_prompt_info() { @@ -65,16 +68,36 @@ __prompt_rerender() { if [[ ${P[vcs]} == "git" ]]; then local git_dirty_marks="" if [[ -n ${P[vcs_dirty]} && ${P[vcs_dirty]} != "0" ]]; then - git_dirty_marks=":&" + git_dirty_marks="(&)" + fi + + local git_log_dir="" + if [[ ${P[vcs_log_ahead]} -gt 0 || ${P[vcs_log_behind]} -gt 0 ]]; then + git_log_dir=":[+${P[vcs_log_ahead]}:-${P[vcs_log_behind]}]" fi prompt_parts_top+=( - "{git:${P[vcs_br]}${git_dirty_marks}}" + "{${git_dirty_marks}git:${P[vcs_br]}${git_log_dir}}" ) if [[ -n ${P[stg]} ]]; then + local stg_dirty_marks="" + if [[ -n ${P[stg_ditry]} && ${P[stg_dirty]} != "0" ]]; then + stg_dirty_marks="(&)" + fi + + local stg_patch="" + if [[ -n ${P[stg_top]} ]]; then + stg_patch=":${P[stg_top]}" + fi + + local stg_pos="" + if [[ ${P[stg_qpos]} -gt 0 || ${P[stg_qlen]} -gt 0 ]]; then + stg_pos=":[${P[stg_qpos]:-0}/${P[stg_qlen]:-0}]" + fi + prompt_parts_top+=( - "{stg:${P[stg_top]}:${P[stg_qpos]}/${P[stg_qlen]}}" + "{stg${stg_patch}${stg_pos}}" ) fi fi @@ -97,26 +120,39 @@ __prompt_rerender() { "[${P[ts]}]" ) - local prompt_marker=">" + local prompt_marker="❯" if [[ $KEYMAP == "vicmd" ]]; then - prompt_marker="<" + prompt_marker="❮" + fi + + local prompt_prefix=":?" + if [[ $G_ASYNC_DONE -eq 1 ]]; then + prompt_prefix="::" fi local -a prompt_parts=() if [[ ${#prompt_parts_top[@]} -gt 0 ]]; then - prompt_parts+=(":: ${(j. .)prompt_parts_top}") + prompt_parts+=("${prompt_prefix} %F{yellow}${(j. .)prompt_parts_top}%f") + else + prompt_parts+=("${prompt_prefix} %F{yellow}-----------%f") fi if [[ ${#prompt_parts_bottom[@]} -gt 0 ]]; then - prompt_parts+=(":: ${(j. .)prompt_parts_bottom}") + prompt_parts+=("${prompt_prefix} %F{blue}${(j. .)prompt_parts_bottom}%f") + else + prompt_parts+=("${prompt_prefix} %F{blue}-----------%f") fi prompt_parts+=( - "$prompt_marker " + "%F{green}$prompt_marker%f " ) local BR=$C_PROMPT_NEWLINE PROMPT="$BR${(pj.$BR.)prompt_parts}" - zle && zle reset-prompt + if [[ $PROMPT != $G_LAST_PROMPT ]]; then + zle && zle .reset-prompt + fi + + G_LAST_PROMPT="$PROMPT" } #------------------------------------------------------------------------------- @@ -134,6 +170,9 @@ __prompt_precmd() { # reset prompt state G_PROMPT_PARTS=() + # set prompt status to rendering + G_ASYNC_DONE=0 + __zle_async_dispatch __zle_async_fd_handler __async_prompt_info __prompt_rerender @@ -149,10 +188,12 @@ __zle_async_fd_handler() { local ZLE_FD=$1 # read in all data that is available - if ! IFS='' read -r ASYNC_RESULT <&"$ZLE_FD"; then + if ! IFS=$'\n' read -r ASYNC_RESULT <&"$ZLE_FD"; then # select marks this fd if we reach EOF, # so handle this specially. __zle_async_detach "$ZLE_FD" + G_ASYNC_DONE=1 + __prompt_rerender return 1 fi @@ -197,8 +238,8 @@ __zle_async_detach() { #------------------------------------------------------------------------------- prompt_asynczle_setup() { - autoload -Uz +X add-zle-hook-widget 2>/dev/null autoload -Uz +X add-zsh-hook 2>/dev/null + autoload -Uz +X add-zle-hook-widget 2>/dev/null add-zsh-hook precmd __prompt_precmd add-zsh-hook preexec __prompt_preexec