mirror of
https://github.com/ddworken/hishtory.git
synced 2024-11-22 08:14:02 +01:00
Fix race condition
This commit is contained in:
parent
82f470f892
commit
49ccce74e1
52
client/testdata/TestTui-InitialInvalidSearch
vendored
52
client/testdata/TestTui-InitialInvalidSearch
vendored
@ -1,29 +1,27 @@
|
|||||||
Warning: failed to search: search query contains unknown search atom 'foo' that doesn't match any column names
|
Search Query: > ls
|
||||||
|
|
||||||
Search Query: > foo:ls
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ Hostname CWD Timestamp Runtime Exit Code Command │
|
||||||
|
│────────────────────────────────────────────────────────────────────────────────────────────────────────│
|
||||||
|
│ localhost /tmp/ Oct 17 2022 21:43:16 PDT 3s 2 ls ~/ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
└────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||||
hiSHtory: Search your shell history • ctrl+h help
|
hiSHtory: Search your shell history • ctrl+h help
|
@ -101,6 +101,9 @@ type model struct {
|
|||||||
|
|
||||||
// The currently executing shell. Defaults to bash if not specified. Used for more precise AI suggestions.
|
// The currently executing shell. Defaults to bash if not specified. Used for more precise AI suggestions.
|
||||||
shellName string
|
shellName string
|
||||||
|
|
||||||
|
// Whether we've finished the first load of results. If we haven't, we refuse to run additional queries to avoid race conditions with how we handle invalid initial queries.
|
||||||
|
hasFinishedFirstLoad bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@ -125,6 +128,8 @@ type asyncQueryFinishedMsg struct {
|
|||||||
maintainCursor bool
|
maintainCursor bool
|
||||||
// An updated search query. May be used for initial queries when they're invalid.
|
// An updated search query. May be used for initial queries when they're invalid.
|
||||||
overriddenSearchQuery *string
|
overriddenSearchQuery *string
|
||||||
|
|
||||||
|
isFirstQuery bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func initialModel(ctx context.Context, shellName, initialQuery string) model {
|
func initialModel(ctx context.Context, shellName, initialQuery string) model {
|
||||||
@ -154,7 +159,7 @@ func initialModel(ctx context.Context, shellName, initialQuery string) model {
|
|||||||
queryInput.SetValue(initialQuery)
|
queryInput.SetValue(initialQuery)
|
||||||
}
|
}
|
||||||
CURRENT_QUERY_FOR_HIGHLIGHTING = initialQuery
|
CURRENT_QUERY_FOR_HIGHLIGHTING = initialQuery
|
||||||
return model{ctx: ctx, spinner: s, isLoading: true, table: nil, tableEntries: []*data.HistoryEntry{}, runQuery: &initialQuery, queryInput: queryInput, help: help.New(), shellName: shellName}
|
return model{ctx: ctx, spinner: s, isLoading: true, table: nil, tableEntries: []*data.HistoryEntry{}, runQuery: &initialQuery, queryInput: queryInput, help: help.New(), shellName: shellName, hasFinishedFirstLoad: false}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m model) Init() tea.Cmd {
|
func (m model) Init() tea.Cmd {
|
||||||
@ -205,13 +210,14 @@ func preventTableOverscrolling(m model) {
|
|||||||
|
|
||||||
func runQueryAndUpdateTable(m model, forceUpdateTable, maintainCursor bool) tea.Cmd {
|
func runQueryAndUpdateTable(m model, forceUpdateTable, maintainCursor bool) tea.Cmd {
|
||||||
if (m.runQuery != nil && *m.runQuery != m.lastQuery) || forceUpdateTable || m.searchErr != nil {
|
if (m.runQuery != nil && *m.runQuery != m.lastQuery) || forceUpdateTable || m.searchErr != nil {
|
||||||
|
// if !m.hasFinishedFirstLoad {
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
query := m.lastQuery
|
query := m.lastQuery
|
||||||
if m.runQuery != nil {
|
if m.runQuery != nil {
|
||||||
query = *m.runQuery
|
query = *m.runQuery
|
||||||
}
|
}
|
||||||
LAST_DISPATCHED_QUERY_ID++
|
queryId := allocateQueryId()
|
||||||
queryId := LAST_DISPATCHED_QUERY_ID
|
|
||||||
LAST_DISPATCHED_QUERY_TIMESTAMP = time.Now()
|
|
||||||
return func() tea.Msg {
|
return func() tea.Msg {
|
||||||
conf := hctx.GetConf(m.ctx)
|
conf := hctx.GetConf(m.ctx)
|
||||||
defaultFilter := conf.DefaultFilter
|
defaultFilter := conf.DefaultFilter
|
||||||
@ -220,7 +226,7 @@ func runQueryAndUpdateTable(m model, forceUpdateTable, maintainCursor bool) tea.
|
|||||||
defaultFilter = ""
|
defaultFilter = ""
|
||||||
}
|
}
|
||||||
rows, entries, searchErr := getRows(m.ctx, conf.DisplayedColumns, m.shellName, defaultFilter, query, PADDED_NUM_ENTRIES)
|
rows, entries, searchErr := getRows(m.ctx, conf.DisplayedColumns, m.shellName, defaultFilter, query, PADDED_NUM_ENTRIES)
|
||||||
return asyncQueryFinishedMsg{queryId, rows, entries, searchErr, forceUpdateTable, maintainCursor, nil}
|
return asyncQueryFinishedMsg{queryId, rows, entries, searchErr, forceUpdateTable, maintainCursor, nil, false}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -337,6 +343,9 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
m.queryInput.SetValue(*msg.overriddenSearchQuery)
|
m.queryInput.SetValue(*msg.overriddenSearchQuery)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if msg.isFirstQuery {
|
||||||
|
m.hasFinishedFirstLoad = true
|
||||||
|
}
|
||||||
return m, nil
|
return m, nil
|
||||||
default:
|
default:
|
||||||
var cmd tea.Cmd
|
var cmd tea.Cmd
|
||||||
@ -895,6 +904,12 @@ func splitQueryArray(initialQueryArray []string) []string {
|
|||||||
return splitQueryArray
|
return splitQueryArray
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func allocateQueryId() int {
|
||||||
|
LAST_DISPATCHED_QUERY_ID++
|
||||||
|
LAST_DISPATCHED_QUERY_TIMESTAMP = time.Now()
|
||||||
|
return LAST_DISPATCHED_QUERY_ID
|
||||||
|
}
|
||||||
|
|
||||||
func TuiQuery(ctx context.Context, shellName string, initialQueryArray []string) error {
|
func TuiQuery(ctx context.Context, shellName string, initialQueryArray []string) error {
|
||||||
initialQueryArray = splitQueryArray(initialQueryArray)
|
initialQueryArray = splitQueryArray(initialQueryArray)
|
||||||
initialQueryWithEscaping, err := buildInitialQueryWithSearchEscaping(initialQueryArray)
|
initialQueryWithEscaping, err := buildInitialQueryWithSearchEscaping(initialQueryArray)
|
||||||
@ -906,18 +921,22 @@ func TuiQuery(ctx context.Context, shellName string, initialQueryArray []string)
|
|||||||
p := tea.NewProgram(initialModel(ctx, shellName, initialQueryWithEscaping), tea.WithOutput(os.Stderr))
|
p := tea.NewProgram(initialModel(ctx, shellName, initialQueryWithEscaping), tea.WithOutput(os.Stderr))
|
||||||
// Async: Get the initial set of rows
|
// Async: Get the initial set of rows
|
||||||
go func() {
|
go func() {
|
||||||
LAST_DISPATCHED_QUERY_ID++
|
queryId := allocateQueryId()
|
||||||
queryId := LAST_DISPATCHED_QUERY_ID
|
|
||||||
LAST_DISPATCHED_QUERY_TIMESTAMP = time.Now()
|
|
||||||
conf := hctx.GetConf(ctx)
|
conf := hctx.GetConf(ctx)
|
||||||
rows, entries, err := getRows(ctx, conf.DisplayedColumns, shellName, conf.DefaultFilter, initialQueryWithEscaping, PADDED_NUM_ENTRIES)
|
rows, entries, err := getRows(ctx, conf.DisplayedColumns, shellName, conf.DefaultFilter, initialQueryWithEscaping, PADDED_NUM_ENTRIES)
|
||||||
if err == nil || initialQueryWithEscaping == "" {
|
if err == nil || initialQueryWithEscaping == "" {
|
||||||
p.Send(asyncQueryFinishedMsg{queryId: queryId, rows: rows, entries: entries, searchErr: err, forceUpdateTable: true, maintainCursor: false, overriddenSearchQuery: nil})
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
p.Send(asyncQueryFinishedMsg{queryId: queryId, rows: rows, entries: entries, searchErr: err, forceUpdateTable: true, maintainCursor: false, overriddenSearchQuery: nil, isFirstQuery: true})
|
||||||
} else {
|
} else {
|
||||||
// The initial query is likely invalid in some way, let's just drop it
|
// The initial query is likely invalid in some way, let's just drop it
|
||||||
emptyQuery := ""
|
emptyQuery := ""
|
||||||
rows, entries, err := getRows(ctx, hctx.GetConf(ctx).DisplayedColumns, shellName, conf.DefaultFilter, emptyQuery, PADDED_NUM_ENTRIES)
|
rows, entries, err := getRows(ctx, hctx.GetConf(ctx).DisplayedColumns, shellName, conf.DefaultFilter, emptyQuery, PADDED_NUM_ENTRIES)
|
||||||
p.Send(asyncQueryFinishedMsg{queryId: queryId, rows: rows, entries: entries, searchErr: err, forceUpdateTable: true, maintainCursor: false, overriddenSearchQuery: &emptyQuery})
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
p.Send(asyncQueryFinishedMsg{queryId: allocateQueryId(), rows: rows, entries: entries, searchErr: err, forceUpdateTable: true, maintainCursor: false, overriddenSearchQuery: &emptyQuery, isFirstQuery: true})
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
// Async: Retrieve additional entries from the backend
|
// Async: Retrieve additional entries from the backend
|
||||||
@ -962,4 +981,3 @@ func TuiQuery(ctx context.Context, shellName string, initialQueryArray []string)
|
|||||||
|
|
||||||
// TODO: support custom key bindings
|
// TODO: support custom key bindings
|
||||||
// TODO: make the help page wrap
|
// TODO: make the help page wrap
|
||||||
// TODO: If the initial query contains dashes, maybe we should smartly escape them?
|
|
||||||
|
Loading…
Reference in New Issue
Block a user