Implement widgets for arrow up/down, minor changes

pull/18/head
Simon Let 6 years ago
parent a3c2190c8a
commit ca660a0e9b
  1. 2
      VERSION
  2. 33
      cmd/collect/main.go
  3. 2
      cmd/daemon/recall.go
  4. 3
      pkg/records/records.go
  5. 59
      pkg/sesshist/sesshist.go
  6. 14
      scripts/hooks.sh
  7. 1
      scripts/shellrc.sh
  8. 60
      scripts/widgets.sh

@ -1 +1 @@
1.1.5 1.1.6

@ -35,21 +35,28 @@ func main() {
if _, err := toml.DecodeFile(configPath, &config); err != nil { if _, err := toml.DecodeFile(configPath, &config); err != nil {
log.Fatal("Error reading config:", err) log.Fatal("Error reading config:", err)
} }
// recall command
recall := flag.Bool("recall", false, "Recall command on position --histno") recall := flag.Bool("recall", false, "Recall command on position --histno")
recallHistno := flag.Int("histno", 0, "Recall command on position --histno") recallHistno := flag.Int("histno", 0, "Recall command on position --histno")
recallPrefix := flag.String("prefix-search", "", "Recall command based on prefix --prefix-search")
// version
showVersion := flag.Bool("version", false, "Show version and exit") showVersion := flag.Bool("version", false, "Show version and exit")
showRevision := flag.Bool("revision", false, "Show git revision and exit") showRevision := flag.Bool("revision", false, "Show git revision and exit")
requireVersion := flag.String("requireVersion", "", "abort if version doesn't match") requireVersion := flag.String("requireVersion", "", "abort if version doesn't match")
requireRevision := flag.String("requireRevision", "", "abort if revision doesn't match") requireRevision := flag.String("requireRevision", "", "abort if revision doesn't match")
// core
cmdLine := flag.String("cmdLine", "", "command line") cmdLine := flag.String("cmdLine", "", "command line")
exitCode := flag.Int("exitCode", -1, "exit code") exitCode := flag.Int("exitCode", -1, "exit code")
shell := flag.String("shell", "", "actual shell") shell := flag.String("shell", "", "actual shell")
uname := flag.String("uname", "", "uname") uname := flag.String("uname", "", "uname")
sessionID := flag.String("sessionId", "", "resh generated session id") sessionID := flag.String("sessionId", "", "resh generated session id")
// recall metadata
recallActions := flag.String("recall-actions", "", "recall actions that took place before executing the command")
// posix variables // posix variables
cols := flag.String("cols", "-1", "$COLUMNS") cols := flag.String("cols", "-1", "$COLUMNS")
lines := flag.String("lines", "-1", "$LINES") lines := flag.String("lines", "-1", "$LINES")
@ -121,6 +128,11 @@ func main() {
log.Println("Option '--recall' only works with '--histno' option - exiting!") log.Println("Option '--recall' only works with '--histno' option - exiting!")
os.Exit(4) os.Exit(4)
} }
if *recallPrefix != "" && *recall == false {
log.Println("Option '--prefix-search' only works with '--recall' option - exiting!")
os.Exit(4)
}
realtimeBefore, err := strconv.ParseFloat(*rtb, 64) realtimeBefore, err := strconv.ParseFloat(*rtb, 64)
if err != nil { if err != nil {
log.Fatal("Flag Parsing error (rtb):", err) log.Fatal("Flag Parsing error (rtb):", err)
@ -150,15 +162,15 @@ func main() {
*gitRemote = "" *gitRemote = ""
} }
if *osReleaseID == "" { // if *osReleaseID == "" {
*osReleaseID = "linux" // *osReleaseID = "linux"
} // }
if *osReleaseName == "" { // if *osReleaseName == "" {
*osReleaseName = "Linux" // *osReleaseName = "Linux"
} // }
if *osReleasePrettyName == "" { // if *osReleasePrettyName == "" {
*osReleasePrettyName = "Linux" // *osReleasePrettyName = "Linux"
} // }
rec := records.Record{ rec := records.Record{
// posix // posix
@ -219,6 +231,9 @@ func main() {
ReshUUID: collect.ReadFileContent(reshUUIDPath), ReshUUID: collect.ReadFileContent(reshUUIDPath),
ReshVersion: Version, ReshVersion: Version,
ReshRevision: Revision, ReshRevision: Revision,
RecallActions: []string{*recallActions},
RecallPrefix: *recallPrefix,
}, },
} }
if *recall { if *recall {

@ -29,7 +29,7 @@ func (h *recallHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
log.Println("Payload:", jsn) log.Println("Payload:", jsn)
return return
} }
cmd, err := h.sesshistDispatch.Recall(rec.SessionID, rec.RecallHistno) cmd, err := h.sesshistDispatch.Recall(rec.SessionID, rec.RecallHistno, rec.RecallPrefix)
if err != nil { if err != nil {
log.Println("/recall - sess id:", rec.SessionID, " - histno:", rec.RecallHistno, " -> ERROR") log.Println("/recall - sess id:", rec.SessionID, " - histno:", rec.RecallHistno, " -> ERROR")
log.Println("Recall error:", err) log.Println("Recall error:", err)

@ -86,6 +86,9 @@ type BaseRecord struct {
RecallStrategy string `json:"recallStrategy,omitempty"` RecallStrategy string `json:"recallStrategy,omitempty"`
RecallActions []string `json:"recallActions,omitempty"` RecallActions []string `json:"recallActions,omitempty"`
// recall command
RecallPrefix string `json:"recallPrefix,omitempty"`
// added by sanitizatizer // added by sanitizatizer
Sanitized bool `json:"sanitized,omitempty"` Sanitized bool `json:"sanitized,omitempty"`
CmdLength int `json:"cmdLength,omitempty"` CmdLength int `json:"cmdLength,omitempty"`

@ -4,6 +4,7 @@ import (
"errors" "errors"
"log" "log"
"strconv" "strconv"
"strings"
"sync" "sync"
"github.com/curusarn/resh/pkg/records" "github.com/curusarn/resh/pkg/records"
@ -94,13 +95,22 @@ func (s *Dispatch) addRecentRecord(sessionID string, record records.Record) erro
} }
session.mutex.Lock() session.mutex.Lock()
defer session.mutex.Unlock() defer session.mutex.Unlock()
session.recent = append(session.recent, record) session.recentRecords = append(session.recentRecords, record)
log.Println("sesshist: record:", record.CmdLine, "; added to session:", sessionID, "; session len:", len(session.recent)) // remove previous occurance of record
for i := len(session.recentCmdLines) - 1; i >= 0; i-- {
if session.recentCmdLines[i] == record.CmdLine {
session.recentCmdLines = append(session.recentCmdLines[:i], session.recentCmdLines[i+1:]...)
}
}
// append new record
session.recentCmdLines = append(session.recentCmdLines, record.CmdLine)
log.Println("sesshist: record:", record.CmdLine, "; added to session:", sessionID,
"; session len:", len(session.recentCmdLines), "; session len w/ dups:", len(session.recentRecords))
return nil return nil
} }
// Recall command from recent session history // Recall command from recent session history
func (s *Dispatch) Recall(sessionID string, histno int) (string, error) { func (s *Dispatch) Recall(sessionID string, histno int, prefix string) (string, error) {
s.mutex.RLock() s.mutex.RLock()
session, found := s.sessions[sessionID] session, found := s.sessions[sessionID]
s.mutex.RUnlock() s.mutex.RUnlock()
@ -108,18 +118,25 @@ func (s *Dispatch) Recall(sessionID string, histno int) (string, error) {
if found == false { if found == false {
return "", errors.New("sesshist ERROR: No session history for SessionID " + sessionID) return "", errors.New("sesshist ERROR: No session history for SessionID " + sessionID)
} }
if prefix == "" {
session.mutex.Lock() session.mutex.Lock()
defer session.mutex.Unlock() defer session.mutex.Unlock()
return session.getRecordByHistno(histno) return session.getRecordByHistno(histno)
}
session.mutex.Lock()
defer session.mutex.Unlock()
return session.searchRecordByPrefix(prefix, histno)
} }
type sesshist struct { type sesshist struct {
recent []records.Record recentRecords []records.Record
recentCmdLines []string // deduplicated
// cmdLines map[string]int
mutex sync.Mutex mutex sync.Mutex
} }
func (s *sesshist) getRecordByHistno(histno int) (string, error) { func (s *sesshist) getRecordByHistno(histno int) (string, error) {
// records get appended to the end of the slice // addRecords() appends records to the end of the slice
// -> this func handles the indexing // -> this func handles the indexing
if histno == 0 { if histno == 0 {
return "", errors.New("sesshist ERROR: 'histno == 0' is not a record from history") return "", errors.New("sesshist ERROR: 'histno == 0' is not a record from history")
@ -127,9 +144,35 @@ func (s *sesshist) getRecordByHistno(histno int) (string, error) {
if histno < 0 { if histno < 0 {
return "", errors.New("sesshist ERROR: 'histno < 0' is a command from future (not supperted yet)") return "", errors.New("sesshist ERROR: 'histno < 0' is a command from future (not supperted yet)")
} }
index := len(s.recent) - histno index := len(s.recentCmdLines) - histno
if index < 0 { if index < 0 {
return "", errors.New("sesshist ERROR: 'histno > number of commands in the session' (" + strconv.Itoa(len(s.recent)) + ")") return "", errors.New("sesshist ERROR: 'histno > number of commands in the session' (" + strconv.Itoa(len(s.recentCmdLines)) + ")")
}
return s.recentCmdLines[index], nil
}
func (s *sesshist) searchRecordByPrefix(prefix string, histno int) (string, error) {
if histno == 0 {
return "", errors.New("sesshist ERROR: 'histno == 0' is not a record from history")
}
if histno < 0 {
return "", errors.New("sesshist ERROR: 'histno < 0' is a command from future (not supperted yet)")
}
index := len(s.recentCmdLines) - histno
if index < 0 {
return "", errors.New("sesshist ERROR: 'histno > number of commands in the session' (" + strconv.Itoa(len(s.recentCmdLines)) + ")")
}
cmdLines := []string{}
for i := len(s.recentCmdLines) - 1; i >= 0; i-- {
if strings.HasPrefix(s.recentCmdLines[i], prefix) {
cmdLines = append(cmdLines, s.recentCmdLines[i])
if len(cmdLines) >= histno {
break
}
}
}
if len(cmdLines) < histno {
return "", errors.New("sesshist ERROR: 'histno > number of commands matching with given prefix' (" + strconv.Itoa(len(cmdLines)) + ")")
} }
return s.recent[index].CmdLine, nil return cmdLines[histno-1], nil
} }

@ -1,11 +1,20 @@
__resh_preexec() { __resh_reset_variables() {
__RESH_HISTNO=0 __RESH_HISTNO=0
__RESH_HISTNO_ZERO_LINE=""
__RESH_HIST_PREV_LINE=""
__RESH_HIST_RECALL_ACTIONS=""
__RESH_HIST_NO_PREFIX_MODE=0
}
__resh_preexec() {
# core # core
__RESH_COLLECT=1 __RESH_COLLECT=1
__RESH_CMDLINE="$1" # not local to preserve it for postcollect (useful as sanity check) __RESH_CMDLINE="$1" # not local to preserve it for postcollect (useful as sanity check)
__resh_collect --cmdLine "$__RESH_CMDLINE" \ __resh_collect --cmdLine "$__RESH_CMDLINE" --recall-actions "$__RESH_HIST_RECALL_ACTIONS" \
&>~/.resh/collect_last_run_out.txt || echo "resh-collect ERROR: $(head -n 1 ~/.resh/collect_last_run_out.txt)" &>~/.resh/collect_last_run_out.txt || echo "resh-collect ERROR: $(head -n 1 ~/.resh/collect_last_run_out.txt)"
__resh_reset_variables
} }
# used for collect and collect --recall # used for collect and collect --recall
@ -90,6 +99,7 @@ __resh_collect() {
-osReleaseIdLike "$__RESH_OS_RELEASE_ID_LIKE" \ -osReleaseIdLike "$__RESH_OS_RELEASE_ID_LIKE" \
-osReleaseName "$__RESH_OS_RELEASE_NAME" \ -osReleaseName "$__RESH_OS_RELEASE_NAME" \
-osReleasePrettyName "$__RESH_OS_RELEASE_PRETTY_NAME" \ -osReleasePrettyName "$__RESH_OS_RELEASE_PRETTY_NAME" \
-histno "$__RESH_HISTNO" \
"$@" "$@"
fi fi
} }

@ -73,6 +73,7 @@ if [ -z "${__RESH_SESSION_ID+x}" ]; then
export __RESH_SESSION_ID; __RESH_SESSION_ID=$(__resh_get_uuid) export __RESH_SESSION_ID; __RESH_SESSION_ID=$(__resh_get_uuid)
export __RESH_SESSION_PID="$$" export __RESH_SESSION_PID="$$"
# TODO add sesson time # TODO add sesson time
__resh_reset_variables
__resh_session_init __resh_session_init
fi fi

@ -2,15 +2,71 @@
# shellcheck source=hooks.sh # shellcheck source=hooks.sh
. ~/.resh/hooks.sh . ~/.resh/hooks.sh
__resh_helper_arrow_pre() {
# set prefix
__RESH_PREFIX=${BUFFER:0:CURSOR}
# cursor not at the end of the line => end "NO_PREFIX_MODE"
[ "$CURSOR" -ne "${#BUFFER}" ] && __RESH_HIST_NO_PREFIX_MODE=0
# if user made any edits from last recall action => restart histno AND deactivate "NO_PREFIX_MODE"
[ "$BUFFER" != "$__RESH_HIST_PREV_LINE" ] && __RESH_HISTNO=0 && __RESH_HIST_NO_PREFIX_MODE=0
# "NO_PREFIX_MODE" => set prefix to empty string
[ "$__RESH_HIST_NO_PREFIX_MODE" -eq 1 ] && __RESH_PREFIX=""
# append curent recall action
__RESH_HIST_RECALL_ACTIONS="$__RESH_HIST_RECALL_ACTIONS;arrow_up:$__RESH_PREFIX"
# histno == 0 => save current line
[ $__RESH_HISTNO -eq 0 ] && __RESH_HISTNO_ZERO_LINE=$BUFFER
}
__resh_helper_arrow_post() {
# cursor at the beginning of the line => activate "NO_PREFIX_MODE"
[ "$CURSOR" -eq 0 ] && __RESH_HIST_NO_PREFIX_MODE=1
# "NO_PREFIX_MODE" => move cursor to the end of the line
[ "$__RESH_HIST_NO_PREFIX_MODE" -eq 1 ] && CURSOR=${#BUFFER}
# save current line so we can spot user edits next time
__RESH_HIST_PREV_LINE=$BUFFER
}
__resh_widget_arrow_up() { __resh_widget_arrow_up() {
# run helper function
__resh_helper_arrow_pre
# increment histno
(( __RESH_HISTNO++ )) (( __RESH_HISTNO++ ))
BUFFER="$(__resh_collect --recall --histno "$__RESH_HISTNO" 2> ~/.resh/arrow_up_last_run_out.txt)" # back at histno == 0 => restore original line
if [ $__RESH_HISTNO -eq 0 ]; then
BUFFER=$__RESH_HISTNO_ZERO_LINE
else
# run recall
local NEW_BUFFER
NEW_BUFFER="$(__resh_collect --recall --histno "$__RESH_HISTNO" --prefix-search "$__RESH_PREFIX" 2> ~/.resh/arrow_up_last_run_out.txt)"
# IF new buffer in non-empty THEN use the new buffer ELSE revert histno change
# shellcheck disable=SC2015
[ ${#NEW_BUFFER} -gt 0 ] && BUFFER=$NEW_BUFFER || (( __RESH_HISTNO-- ))
fi
# run post helper
__resh_helper_arrow_post
} }
__resh_widget_arrow_down() { __resh_widget_arrow_down() {
# run helper function
__resh_helper_arrow_pre
# increment histno
(( __RESH_HISTNO-- )) (( __RESH_HISTNO-- ))
BUFFER="$(__resh_collect --recall --histno "$__RESH_HISTNO" 2> ~/.resh/arrow_down_last_run_out.txt)" # prevent HISTNO from getting negative (for now)
[ $__RESH_HISTNO -lt 0 ] && __RESH_HISTNO=0
# back at histno == 0 => restore original line
if [ $__RESH_HISTNO -eq 0 ]; then
BUFFER=$__RESH_HISTNO_ZERO_LINE
else
# run recall
local NEW_BUFFER
NEW_BUFFER="$(__resh_collect --recall --histno "$__RESH_HISTNO" --prefix-search "$__RESH_PREFIX" 2> ~/.resh/arrow_down_last_run_out.txt)"
# IF new buffer in non-empty THEN use the new buffer ELSE revert histno change
# shellcheck disable=SC2015
[ ${#NEW_BUFFER} -gt 0 ] && BUFFER=$NEW_BUFFER || (( __RESH_HISTNO++ ))
fi
__resh_helper_arrow_post
} }
__resh_widget_control_R() { __resh_widget_control_R() {
local __RESH_LBUFFER=${BUFFER:0:CURSOR}
__RESH_HIST_RECALL_ACTIONS="$__RESH_HIST_RECALL_ACTIONS;control_R:$__RESH_LBUFFER"
# resh-collect --hstr # resh-collect --hstr
hstr hstr
} }

Loading…
Cancel
Save