├── .dockerignore
├── .errcheck_excludes.txt
├── .github
├── push_event.json
├── slsa
│ ├── .slsa-goreleaser-darwin-amd64.yml
│ ├── .slsa-goreleaser-darwin-arm64.yml
│ ├── .slsa-goreleaser-freebsd-amd64.yml
│ ├── .slsa-goreleaser-linux-amd64.yml
│ ├── .slsa-goreleaser-linux-arm64.yml
│ ├── .slsa-goreleaser-linux-arm7.yml
│ └── .slsa-goreleaser-netbsd-amd64.yml
└── workflows
│ ├── codeql-analysis.yml
│ ├── distro-smoke-test.yml
│ ├── docker-compose-test.yml
│ ├── go-test.yml
│ ├── pre-commit.yml
│ ├── server-releaser.yml
│ └── slsa-releaser.yml
├── .gitignore
├── .pre-commit-config.yaml
├── LICENSE
├── Makefile
├── README.md
├── VERSION
├── backend
├── server
│ ├── Dockerfile
│ ├── docker-compose.yml
│ ├── internal
│ │ ├── database
│ │ │ ├── db.go
│ │ │ ├── device.go
│ │ │ ├── historyentries.go
│ │ │ └── usagedata.go
│ │ ├── release
│ │ │ ├── release.go
│ │ │ └── release_test.go
│ │ └── server
│ │ │ ├── api_handlers.go
│ │ │ ├── debug_handlers.go
│ │ │ ├── middleware.go
│ │ │ ├── middleware_test.go
│ │ │ ├── server_test.go
│ │ │ ├── srv.go
│ │ │ └── util.go
│ └── server.go
└── web
│ ├── caddy
│ ├── Caddyfile
│ └── Dockerfile
│ └── landing
│ └── www
│ ├── .gitignore
│ ├── img
│ ├── aidemo.png
│ ├── demo.gif
│ └── webui.png
│ ├── index.html
│ └── install.py
├── client
├── ai
│ └── ai.go
├── cmd
│ ├── configAdd.go
│ ├── configDelete.go
│ ├── configGet.go
│ ├── configKeyBindings.go
│ ├── configSet.go
│ ├── enableDisable.go
│ ├── export.go
│ ├── import.go
│ ├── install.go
│ ├── install_test.go
│ ├── query.go
│ ├── redact.go
│ ├── reupload.go
│ ├── root.go
│ ├── saveHistoryEntry.go
│ ├── saveHistoryEntry_test.go
│ ├── status.go
│ ├── syncing.go
│ ├── update.go
│ └── webui.go
├── data
│ ├── data.go
│ └── data_test.go
├── fuzz_test.go
├── hctx
│ └── hctx.go
├── integration_test.go
├── lib
│ ├── config.fish
│ ├── config.sh
│ ├── config.zsh
│ ├── lib.go
│ ├── lib_test.go
│ ├── net.go
│ ├── net_disabled.go
│ ├── slsa.go
│ └── slsa_test.go
├── posttest
│ └── main.go
├── table
│ ├── table.go
│ └── table_test.go
├── testdata
│ ├── TestBashOrderingBug-Export
│ ├── TestChangeSyncingStatus-Offline
│ ├── TestChangeSyncingStatus-Online
│ ├── TestDefaultSearchColumns-Default-Echo
│ ├── TestDefaultSearchColumns-Default-Hi
│ ├── TestDefaultSearchColumns-MyCol-bar
│ ├── TestDefaultSearchColumns-MyCol-baz
│ ├── TestDefaultSearchColumns-NoCWD-Echo
│ ├── TestDefaultSearchColumns-NoCWD-Hi
│ ├── TestDefaultSearchColumns-NoCWDHostname-Echo
│ ├── TestDefaultSearchColumns-NoCWDHostname-Hi
│ ├── TestExportJson
│ ├── TestFish-table
│ ├── TestImportHistory-export
│ ├── TestInstallSkipConfigModification-InstallOutput-darwin
│ ├── TestInstallSkipConfigModification-InstallOutput-linux
│ ├── TestSortByConsistentTimezone-export
│ ├── TestSortByConsistentTimezone-query
│ ├── TestStatusFullConfig
│ ├── TestTimestampFormat-query
│ ├── TestTimestampFormat-tquery
│ ├── TestTui-AiQuery
│ ├── TestTui-AiQuery-Disabled
│ ├── TestTui-ColoredOutput-darwin-23
│ ├── TestTui-ColoredOutput-linux-actions
│ ├── TestTui-ColoredOutputWithCustomColorScheme-darwin-23
│ ├── TestTui-ColoredOutputWithCustomColorScheme-linux-actions
│ ├── TestTui-ColoredOutputWithDefaultFilter-darwin-23
│ ├── TestTui-ColoredOutputWithDefaultFilter-linux-actions
│ ├── TestTui-ColoredOutputWithSearch-Highlight-darwin-23
│ ├── TestTui-ColoredOutputWithSearch-Highlight-linux-actions
│ ├── TestTui-ColoredOutputWithSearch-darwin-23
│ ├── TestTui-ColoredOutputWithSearch-linux-actions
│ ├── TestTui-DefaultColorScheme
│ ├── TestTui-DefaultFilter-Deleted
│ ├── TestTui-DefaultFilter-DeletedWithText
│ ├── TestTui-DefaultFilter-Enabled
│ ├── TestTui-DefaultFilter-EnabledAdditionalQuery
│ ├── TestTui-Delete
│ ├── TestTui-DeleteAgain
│ ├── TestTui-DeleteAgainStill
│ ├── TestTui-DeleteStill
│ ├── TestTui-Escaping
│ ├── TestTui-Exit-darwin
│ ├── TestTui-Exit-linux
│ ├── TestTui-ExportWithAdditionalEntries
│ ├── TestTui-ExportWithEvenMoreEntries
│ ├── TestTui-ForcedCompactMode
│ ├── TestTui-FullScreenCompactRender
│ ├── TestTui-FullScreenHelp
│ ├── TestTui-FullScreenRender
│ ├── TestTui-HelpPage
│ ├── TestTui-HelpPageClosed
│ ├── TestTui-Initial
│ ├── TestTui-InitialInvalidSearch
│ ├── TestTui-InvalidSearch
│ ├── TestTui-InvalidSearchBecomesValid
│ ├── TestTui-JumpCursor
│ ├── TestTui-KeyBindings-Configured
│ ├── TestTui-KeyBindings-Default
│ ├── TestTui-KeyBindings-Help
│ ├── TestTui-LeftScroll
│ ├── TestTui-LongDirectoryName
│ ├── TestTui-LongQuery
│ ├── TestTui-Offline
│ ├── TestTui-OfflineInvalid
│ ├── TestTui-Resize
│ ├── TestTui-RightScroll
│ ├── TestTui-RightScrollDirectoryTwo
│ ├── TestTui-RightScrollTwo
│ ├── TestTui-Search
│ ├── TestTui-SearchBackslash
│ ├── TestTui-SearchColonDoubleQuoted
│ ├── TestTui-SearchColonError
│ ├── TestTui-SearchColonEscaped
│ ├── TestTui-SearchQuoteDash
│ ├── TestTui-SearchQuoted
│ ├── TestTui-SearchUnquoted
│ ├── TestTui-SelectAndCd
│ ├── TestTui-SmallTerminal
│ ├── TestTui-TiniestTerminal
│ ├── TestTui-TinyTerminal
│ ├── TestTui-TinyTerminalHelp
│ ├── TestTuiBench-Query
│ ├── testControlR-AdvancedSearch
│ ├── testControlR-ControlC-bash-darwin
│ ├── testControlR-ControlC-bash-linux
│ ├── testControlR-ControlC-zsh-darwin
│ ├── testControlR-ControlC-zsh-linux
│ ├── testControlR-DisplayMultiline-bash
│ ├── testControlR-DisplayMultiline-fish
│ ├── testControlR-DisplayMultiline-zsh
│ ├── testControlR-Final
│ ├── testControlR-Initial
│ ├── testControlR-InitialExport
│ ├── testControlR-InitialSearch
│ ├── testControlR-InitialSearchExpanded
│ ├── testControlR-InitialSearchNoResults
│ ├── testControlR-InitialSearchNoResultsThenFoundResults
│ ├── testControlR-Search
│ ├── testControlR-SelectMultiline-bash-darwin
│ ├── testControlR-SelectMultiline-bash-linux
│ ├── testControlR-SelectMultiline-zsh-darwin
│ ├── testControlR-SelectMultiline-zsh-linux
│ ├── testControlR-bash-Disabled-darwin
│ ├── testControlR-bash-Disabled-linux
│ ├── testControlR-customColumn
│ ├── testControlR-displayedColumns
│ ├── testControlR-zsh-Disabled-darwin
│ ├── testControlR-zsh-Disabled-linux
│ ├── testCustomColumns-initHistory
│ ├── testCustomColumns-query-isAction=false
│ ├── testCustomColumns-query-isAction=true
│ ├── testCustomColumns-tquery-bash
│ ├── testCustomColumns-tquery-bash-isAction
│ ├── testCustomColumns-tquery-zsh
│ ├── testCustomColumns-tquery-zsh-isAction
│ ├── testDisplayTable-customColumns
│ ├── testDisplayTable-customColumns-2
│ ├── testDisplayTable-customColumns-3
│ ├── testDisplayTable-customColumns-multiLineCommand
│ ├── testDisplayTable-customColumns-trulyCustom
│ ├── testDisplayTable-defaultColumns
│ ├── testIntegrationWithNewDevice-bash
│ ├── testIntegrationWithNewDevice-tablebash
│ ├── testIntegrationWithNewDevice-tablezsh
│ ├── testIntegrationWithNewDevice-zsh
│ ├── testPresaving-query
│ ├── testPresavingOffline-query-missing
│ ├── testPresavingOffline-query-present
│ ├── testRemoveDuplicateRows-enabled-export
│ ├── testRemoveDuplicateRows-enabled-query
│ ├── testRemoveDuplicateRows-enabled-tquery
│ ├── testRemoveDuplicateRows-export
│ ├── testRemoveDuplicateRows-query
│ ├── testRemoveDuplicateRows-tquery
│ ├── testTabCompletion-suggestions-fish
│ ├── testTabCompletion-suggestions-zsh
│ ├── testUninstall-post-uninstall
│ ├── testUninstall-post-uninstall-bash-darwin
│ ├── testUninstall-post-uninstall-bash-linux
│ ├── testUninstall-post-uninstall-zsh-darwin
│ ├── testUninstall-post-uninstall-zsh-linux
│ ├── testUninstall-recorded
│ ├── testUninstall-uninstall-bash
│ ├── testUninstall-uninstall-zsh
│ ├── unittestTable-truncatedTable
│ ├── unittestTable-truncatedTable-right1
│ ├── unittestTable-truncatedTable-right2
│ └── unittestTable-truncatedTable-right3
├── testutils.go
├── tui
│ ├── keybindings
│ │ └── keybindings.go
│ ├── tui.go
│ └── tui_test.go
└── webui
│ ├── templates
│ └── webui.html
│ └── webui.go
├── demo.vhs
├── docs
└── offline-binary.md
├── go.mod
├── go.sum
├── hishtory.go
├── scripts
├── actions-sign.py
├── actions-validate.py
└── client-ldflags
└── shared
├── ai
├── ai.go
└── ai_test.go
├── data.go
├── testutils
└── testutils.go
├── time.go
├── utils.go
├── version.go
└── version_test.go
/.dockerignore:
--------------------------------------------------------------------------------
1 | .git
2 | node_modules/
3 |
--------------------------------------------------------------------------------
/.errcheck_excludes.txt:
--------------------------------------------------------------------------------
1 | (net/http.ResponseWriter).Write
2 | (*gorm.io/gorm.DB).AutoMigrate
3 | os.Setenv
4 | os.Unsetenv
5 | (*os.File).Close
6 | (io.ReadCloser).Close
7 | (*github.com/gofrs/flock.Flock).Unlock
8 | (*database/sql.Rows).Close
9 | (*github.com/DataDog/datadog-go/statsd.Client).Count
10 | (*github.com/DataDog/datadog-go/statsd.Client).Incr
11 | (*github.com/DataDog/datadog-go/statsd.Client).Distribution
12 | (*github.com/schollz/progressbar/v3.ProgressBar).Finish
13 | (*github.com/DataDog/datadog-go/statsd.Client).Close
14 |
--------------------------------------------------------------------------------
/.github/push_event.json:
--------------------------------------------------------------------------------
1 | {
2 | "push": {
3 | "head": {
4 | "ref": "users/foo/update-action"
5 | },
6 | "base": {
7 | "ref": "users/foo/update-action"
8 | }
9 | },
10 | "head_commit": {
11 | "message": "build latest"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/.github/slsa/.slsa-goreleaser-darwin-amd64.yml:
--------------------------------------------------------------------------------
1 | version: 1
2 |
3 | env:
4 | - CGO_ENABLED=0
5 |
6 | flags:
7 | - -trimpath
8 |
9 | goos: darwin
10 | goarch: amd64
11 |
12 | binary: hishtory-{{ .Os }}-{{ .Arch }}
13 |
14 | ldflags:
15 | - '{{ .Env.VERSION_LDFLAGS }}'
16 |
--------------------------------------------------------------------------------
/.github/slsa/.slsa-goreleaser-darwin-arm64.yml:
--------------------------------------------------------------------------------
1 | version: 1
2 |
3 | env:
4 | - CGO_ENABLED=0
5 |
6 | flags:
7 | - -trimpath
8 |
9 | goos: darwin
10 | goarch: arm64
11 |
12 | binary: hishtory-{{ .Os }}-{{ .Arch }}
13 |
14 | ldflags:
15 | - '{{ .Env.VERSION_LDFLAGS }}'
16 |
--------------------------------------------------------------------------------
/.github/slsa/.slsa-goreleaser-freebsd-amd64.yml:
--------------------------------------------------------------------------------
1 | version: 1
2 |
3 | env:
4 | - CGO_ENABLED=0
5 |
6 | flags:
7 | - -trimpath
8 |
9 | goos: freebsd
10 | goarch: amd64
11 |
12 | binary: hishtory-{{ .Os }}-{{ .Arch }}
13 |
14 | ldflags:
15 | - '{{ .Env.VERSION_LDFLAGS }}'
16 |
--------------------------------------------------------------------------------
/.github/slsa/.slsa-goreleaser-linux-amd64.yml:
--------------------------------------------------------------------------------
1 | version: 1
2 |
3 | env:
4 | - CGO_ENABLED=0
5 |
6 | flags:
7 | - -trimpath
8 |
9 | goos: linux
10 | goarch: amd64
11 |
12 | binary: hishtory-{{ .Os }}-{{ .Arch }}
13 |
14 | ldflags:
15 | - '{{ .Env.VERSION_LDFLAGS }}'
16 |
--------------------------------------------------------------------------------
/.github/slsa/.slsa-goreleaser-linux-arm64.yml:
--------------------------------------------------------------------------------
1 | version: 1
2 |
3 | env:
4 | - CGO_ENABLED=0
5 |
6 | flags:
7 | - -trimpath
8 |
9 | goos: linux
10 | goarch: arm64
11 |
12 | binary: hishtory-{{ .Os }}-{{ .Arch }}
13 |
14 | ldflags:
15 | - '{{ .Env.VERSION_LDFLAGS }}'
16 |
--------------------------------------------------------------------------------
/.github/slsa/.slsa-goreleaser-linux-arm7.yml:
--------------------------------------------------------------------------------
1 | version: 1
2 |
3 | env:
4 | - CGO_ENABLED=0
5 |
6 | flags:
7 | - -trimpath
8 |
9 | goos: linux
10 | goarch: arm
11 |
12 | binary: hishtory-{{ .Os }}-{{ .Arch }}
13 |
14 | ldflags:
15 | - '{{ .Env.VERSION_LDFLAGS }}'
16 |
--------------------------------------------------------------------------------
/.github/slsa/.slsa-goreleaser-netbsd-amd64.yml:
--------------------------------------------------------------------------------
1 | version: 1
2 |
3 | env:
4 | - CGO_ENABLED=0
5 |
6 | flags:
7 | - -trimpath
8 |
9 | goos: netbsd
10 | goarch: amd64
11 |
12 | binary: hishtory-{{ .Os }}-{{ .Arch }}
13 |
14 | ldflags:
15 | - '{{ .Env.VERSION_LDFLAGS }}'
16 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | name: "CodeQL"
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | # The branches below must be a subset of the branches above
8 | branches: [ master ]
9 | schedule:
10 | - cron: '16 13 * * 4'
11 |
12 | jobs:
13 | analyze:
14 | name: Analyze
15 | runs-on: ubuntu-latest
16 | permissions:
17 | actions: read
18 | contents: read
19 | security-events: write
20 |
21 | strategy:
22 | fail-fast: false
23 | matrix:
24 | language: [ 'go' ]
25 |
26 | steps:
27 | - name: Checkout repository
28 | uses: actions/checkout@v3
29 | - name: Initialize CodeQL
30 | uses: github/codeql-action/init@v2
31 | with:
32 | languages: ${{ matrix.language }}
33 | - name: Autobuild
34 | uses: github/codeql-action/autobuild@v2
35 | - name: Perform CodeQL Analysis
36 | if: ${{ !startsWith(github.event.head_commit.message, 'Release') }}
37 | uses: github/codeql-action/analyze@v2
38 |
--------------------------------------------------------------------------------
/.github/workflows/distro-smoke-test.yml:
--------------------------------------------------------------------------------
1 | name: Smoke Test
2 |
3 | on:
4 | workflow_dispatch:
5 | pull_request:
6 | schedule:
7 | - cron: '0 0 * * *'
8 | push:
9 | branches: [ master ]
10 |
11 | jobs:
12 | test:
13 | strategy:
14 | matrix:
15 | distro: ['ubuntu:latest', 'fedora:latest', 'debian:latest', 'archlinux:latest']
16 | fail-fast: false
17 | runs-on: ubuntu-latest
18 | container: ${{ matrix.distro }}
19 | steps:
20 | - name: Debian-based Setup
21 | if: ${{ matrix.distro == 'ubuntu:latest' || matrix.distro == 'debian:latest' }}
22 | run: |
23 |
24 | # Install our dependencies
25 | apt-get update
26 | apt-get install -y zsh tmux fish ca-certificates make build-essential gcc psmisc
27 |
28 | # Work around a weird bug where zsh on ubuntu actions gives that directory 0777 which makes zsh refuse to start
29 | chmod 0755 -R /usr/share/zsh/
30 | - name: DNF-based Setup
31 | if: ${{ matrix.distro == 'fedora:latest' || matrix.distro == 'rockylinux:latest' }}
32 | run: |
33 |
34 | # Install our dependencies
35 | sudo dnf update -y
36 | sudo dnf install -y zsh tmux fish make gcc psmisc
37 | - name: Arch-based Setup
38 | if: ${{ matrix.distro == 'archlinux:latest' }}
39 | run: |
40 |
41 | # Install our dependencies
42 | pacman -Sy --noconfirm zsh tmux fish make gcc psmisc python-pip openssl python-pyopenssl
43 | - uses: actions/checkout@v4
44 | - name: Set up Go
45 | uses: actions/setup-go@v4
46 | with:
47 | go-version: 1.23
48 | - name: Go test
49 | if: ${{ !startsWith(github.event.head_commit.message, 'Release') }}
50 | env:
51 | DD_API_KEY: ${{ secrets.DD_API_KEY }}
52 | OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
53 | run: |
54 | go install gotest.tools/gotestsum@bc98120
55 | make ftest FILTER=TestInstallViaPythonScriptFromHead
56 | # - name: Setup tmate session
57 | # if: ${{ failure() }}
58 | # uses: mxschmitt/action-tmate@v3
59 | # with:
60 | # limit-access-to-actor: true
61 |
--------------------------------------------------------------------------------
/.github/workflows/docker-compose-test.yml:
--------------------------------------------------------------------------------
1 | name: Self-Hosting Docker Compose Tests
2 |
3 | on:
4 | workflow_dispatch:
5 | pull_request:
6 | push:
7 | branches: [ master ]
8 |
9 | jobs:
10 | test:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v3
14 | - name: Set up Go
15 | uses: actions/setup-go@v4
16 | with:
17 | go-version: 1.23
18 | - name: Docker Compose setup
19 | run: |
20 | set -euo pipefail
21 | sudo apt-get update
22 | sudo apt-get install -y zsh fish
23 | curl -fsSL https://get.docker.com | sudo sh
24 | sudo chmod 0755 -R /usr/share/zsh/ # Work around a weird bug where zsh on ubuntu actions gives that diretory 0777 which makes zsh refuse to start
25 | sudo hostname ghaction-runner-hostname # Set a consistent hostname so we can run tests that depend on it
26 | docker compose -f backend/server/docker-compose.yml build
27 | HISHTORY_COMPOSE_TEST=1 docker compose -f backend/server/docker-compose.yml up -d
28 | export HISHTORY_SERVER=http://localhost
29 | go build
30 | ./hishtory install
31 | - name: Docker Compose test
32 | shell: bash -il {0}
33 | run: |
34 | set -eo pipefail
35 | export HISHTORY_SERVER=http://localhost
36 | source ~/.bashrc
37 | # Check that hishtory query runs without errors
38 | ./hishtory query
39 | # Run a command such that hishtory will record it
40 | echo -e 'ls -Slah /\n' | zsh -is
41 | # Sleep to ensure there is time for it to be recorded, since recordings are async
42 | sleep 1
43 | # Check that it was recorded
44 | ./hishtory export | grep "ls -Slah /"
45 | # Check that we can redact it
46 | HISHTORY_REDACT_FORCE=1 ./hishtory redact ls Slah
47 | # And that it was redacted
48 | ! (./hishtory export | grep "ls -Slah /")
49 | # Assert that the entry is syncing properly
50 | ./hishtory status -v | grep 'Sync Status: Synced'
51 | # And that we are properly using the self-hosted server
52 | ./hishtory status -v | grep 'Sync Server: http://localhost'
53 | # Show the full status output for debugging
54 | ./hishtory status -v
55 | # - name: Setup tmate session
56 | # # if: ${{ failure() }}
57 | # uses: mxschmitt/action-tmate@v3
58 | # with:
59 | # limit-access-to-actor: true
--------------------------------------------------------------------------------
/.github/workflows/pre-commit.yml:
--------------------------------------------------------------------------------
1 | name: Pre-Commit
2 |
3 | on:
4 | pull_request:
5 | push:
6 | branches: [ master ]
7 |
8 | jobs:
9 | pre-commit:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v3
13 | - uses: actions/setup-python@v3
14 | - uses: actions/setup-go@v4
15 | with:
16 | go-version: 1.23
17 | - name: Install dependencies
18 | run: |
19 |
20 | go install honnef.co/go/tools/cmd/staticcheck@latest
21 | go install github.com/kisielk/errcheck@latest
22 | go install mvdan.cc/gofumpt@latest
23 | go install github.com/daixiang0/gci@latest
24 | - uses: pre-commit/action@v3.0.0
25 | with:
26 | extra_args: --all-files
27 |
28 |
--------------------------------------------------------------------------------
/.github/workflows/server-releaser.yml:
--------------------------------------------------------------------------------
1 | name: Server Releaser
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | tags:
7 | - "*"
8 |
9 | permissions:
10 | contents: write
11 |
12 | jobs:
13 | releases-matrix:
14 | name: Release Go Binary
15 | runs-on: ubuntu-latest
16 | strategy:
17 | matrix:
18 | goos: [linux, darwin]
19 | goarch: [amd64, arm, arm64]
20 | exclude:
21 | - goos: darwin
22 | goarch: arm
23 | steps:
24 | - uses: actions/checkout@v2
25 | - name: Set up Go
26 | uses: actions/setup-go@v4
27 | with:
28 | go-version: 1.23
29 | - name: Build server binary
30 | run: |
31 | GOARCH=${{ matrix.goarch }} GOOS=${{ matrix.goos }} go build -o hishtory-server-${{ matrix.goos }}-${{ matrix.goarch }} backend/server/server.go
32 | - name: Release
33 | uses: softprops/action-gh-release@1e07f4398721186383de40550babbdf2b84acfc5
34 | if: ${{ startsWith(github.ref, 'refs/tags/') }}
35 | with:
36 | files: |
37 | hishtory-server-${{ matrix.goos }}-${{ matrix.goarch }}
38 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | web/landing/www/binaries/hishtory-linux
2 | hishtory
3 | backend/server/server
4 | postgres-data/
5 | server
6 | !backend/server
7 | .DS_Store
8 | node_modules/
9 | package.json
10 | package-lock.json
11 | .prettierrc
12 | *.cpuprof
13 |
14 | # VS Code settings
15 | .vscode/
16 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/Bahjat/pre-commit-golang
3 | rev: bdba95f94147c2f5da7eda81e15cdd92c41758ba
4 | hooks:
5 | - id: go-vet
6 | - id: go-static-check # install https://staticcheck.io/docs/
7 | - id: golangci-lint # requires github.com/golangci/golangci-lint
8 | - repo: local
9 | hooks:
10 | - id: go-errcheck
11 | name: go-errcheck
12 | entry: errcheck -exclude .errcheck_excludes.txt ./...
13 | language: system
14 | pass_filenames: false
15 | - id: make-fmt # requires 'go install mvdan.cc/gofumpt@latest' and 'go install github.com/daixiang0/gci@latest'
16 | name: make-fmt
17 | entry: make fmt
18 | language: system
19 | pass_filenames: false
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 David Dworken
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/VERSION:
--------------------------------------------------------------------------------
1 | 335
2 |
--------------------------------------------------------------------------------
/backend/server/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM golang:1.23.0-alpine3.20 AS builder
2 |
3 | WORKDIR /app
4 | RUN apk add --update --no-cache --virtual .build-deps build-base
5 | COPY go.mod go.sum ./
6 | RUN go mod download
7 | COPY . ./
8 | ARG GOARCH
9 | RUN GOARCH=${GOARCH} go build -o /server -ldflags "-X main.ReleaseVersion=v0.`cat VERSION`" backend/server/server.go && \
10 | apk del .build-deps
11 |
12 | FROM alpine:3.17
13 | COPY --from=builder /server /server
14 | CMD ["/server"]
15 |
--------------------------------------------------------------------------------
/backend/server/docker-compose.yml:
--------------------------------------------------------------------------------
1 | # A docker-compose file to host a hiSHtory backend. To use:
2 | # 1. Update TODO_YOUR_POSTGRES_PASSWORD_HERE
3 | # 2. `docker compose -f backend/server/docker-compose.yml build`
4 | # 3. `docker compose -f backend/server/docker-compose.yml up`
5 | # 4. Point your hiSHtory client at the server by putting `export HISHTORY_SERVER=http://1.2.3.4` in your shellrc
6 | # 5. Run `hishtory init` to initialize hiSHtory with the local server
7 | # 6. [Optional, but recommended] Add a TLS proxy to enable https
8 | version: "3.8"
9 | networks:
10 | hishtory:
11 | driver: bridge
12 | services:
13 | postgres:
14 | image: postgres
15 | restart: unless-stopped
16 | networks:
17 | - hishtory
18 | environment:
19 | POSTGRES_PASSWORD: TODO_YOUR_POSTGRES_PASSWORD_HERE
20 | POSTGRES_DB: hishtory
21 | PGDATA: /var/lib/postgresql/data/pgdata
22 | volumes:
23 | - postgres-data:/var/lib/postgresql/data
24 | healthcheck:
25 | test: pg_isready -U postgres
26 | interval: 10s
27 | timeout: 3s
28 | hishtory:
29 | depends_on:
30 | postgres:
31 | condition: service_healthy
32 | networks:
33 | - hishtory
34 | build:
35 | context: ../../
36 | dockerfile: ./backend/server/Dockerfile
37 | restart: unless-stopped
38 | deploy:
39 | restart_policy:
40 | condition: on-failure
41 | delay: 3s
42 | environment:
43 | HISHTORY_POSTGRES_DB: postgresql://postgres:TODO_YOUR_POSTGRES_PASSWORD_HERE@postgres:5432/hishtory?sslmode=disable
44 | HISHTORY_COMPOSE_TEST: $HISHTORY_COMPOSE_TEST
45 | ports:
46 | - 80:8080
47 | volumes:
48 | postgres-data:
49 |
--------------------------------------------------------------------------------
/backend/server/internal/database/device.go:
--------------------------------------------------------------------------------
1 | package database
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "time"
7 | )
8 |
9 | type Device struct {
10 | UserId string `json:"user_id"`
11 | DeviceId string `json:"device_id"`
12 | // The IP address that was used to register the device. Recorded so
13 | // that I can count how many people are using hishtory and roughly
14 | // from where. If you would like this deleted, please email me at
15 | // david@daviddworken.com and I can clear it from your device entries.
16 | RegistrationIp string `json:"registration_ip"`
17 | RegistrationDate time.Time `json:"registration_date"`
18 | // Test devices, that should be aggressively cleaned from the DB
19 | IsIntegrationTestDevice bool `json:"is_integration_test_device"`
20 | // Whether this device was uninstalled
21 | UninstallDate time.Time `json:"uninstall_date"`
22 | }
23 |
24 | func (db *DB) CountAllDevices(ctx context.Context) (int64, error) {
25 | var numDevices int64 = 0
26 | tx := db.WithContext(ctx).Model(&Device{}).Count(&numDevices)
27 | if tx.Error != nil {
28 | return 0, fmt.Errorf("tx.Error: %w", tx.Error)
29 | }
30 |
31 | return numDevices, nil
32 | }
33 |
34 | func (db *DB) CountDevicesForUser(ctx context.Context, userID string) (int64, error) {
35 | var existingDevicesCount int64
36 | tx := db.WithContext(ctx).Model(&Device{}).Where("user_id = ?", userID).Count(&existingDevicesCount)
37 | if tx.Error != nil {
38 | return 0, fmt.Errorf("tx.Error: %w", tx.Error)
39 | }
40 |
41 | return existingDevicesCount, nil
42 | }
43 |
44 | func (db *DB) CreateDevice(ctx context.Context, device *Device) error {
45 | tx := db.WithContext(ctx).Create(device)
46 | if tx.Error != nil {
47 | return fmt.Errorf("tx.Error: %w", tx.Error)
48 | }
49 |
50 | return nil
51 | }
52 |
53 | func (db *DB) DevicesForUser(ctx context.Context, userID string) ([]*Device, error) {
54 | var devices []*Device
55 | tx := db.WithContext(ctx).Where("user_id = ? AND (uninstall_date IS NULL OR uninstall_date < '1971-01-01')", userID).Find(&devices)
56 | if tx.Error != nil {
57 | return nil, fmt.Errorf("tx.Error: %w", tx.Error)
58 | }
59 |
60 | return devices, nil
61 | }
62 |
--------------------------------------------------------------------------------
/backend/server/internal/release/release_test.go:
--------------------------------------------------------------------------------
1 | package release
2 |
3 | import (
4 | "strings"
5 | "testing"
6 |
7 | "github.com/ddworken/hishtory/shared/testutils"
8 |
9 | "github.com/stretchr/testify/require"
10 | )
11 |
12 | func TestUpdateReleaseVersion(t *testing.T) {
13 | if !testutils.IsOnline() {
14 | t.Skip("skipping because we're currently offline")
15 | }
16 |
17 | // Check that ReleaseVersion hasn't been set yet
18 | if Version != "UNKNOWN" {
19 | t.Fatalf("initial ReleaseVersion isn't as expected: %#v", Version)
20 | }
21 |
22 | // Update it
23 | err := UpdateReleaseVersion()
24 | if err != nil {
25 | t.Fatalf("updateReleaseVersion failed: %v", err)
26 | }
27 |
28 | // If ReleaseVersion is still unknown, skip because we're getting rate limited
29 | if Version == "UNKNOWN" {
30 | t.Skip()
31 | }
32 | // Otherwise, check that the new value looks reasonable
33 | if !strings.HasPrefix(Version, "v0.") {
34 | t.Fatalf("ReleaseVersion wasn't updated to contain a version: %#v", Version)
35 | }
36 | }
37 |
38 | func TestDecrement(t *testing.T) {
39 | pv, err := decrementVersion("v0.100")
40 | require.NoError(t, err)
41 | require.Equal(t, "v0.99", pv)
42 | }
43 |
--------------------------------------------------------------------------------
/backend/server/internal/server/util.go:
--------------------------------------------------------------------------------
1 | package server
2 |
3 | import (
4 | "fmt"
5 | "math"
6 | "net/http"
7 | pprofhttp "net/http/pprof"
8 | "os"
9 | "runtime"
10 | "strconv"
11 |
12 | httptrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/net/http"
13 | "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
14 | "gopkg.in/DataDog/dd-trace-go.v1/profiler"
15 | )
16 |
17 | func getMaximumNumberOfAllowedUsers() int {
18 | maxNumUsersStr := os.Getenv("HISHTORY_MAX_NUM_USERS")
19 | if maxNumUsersStr == "" {
20 | return math.MaxInt
21 | }
22 | maxNumUsers, err := strconv.Atoi(maxNumUsersStr)
23 | if err != nil {
24 | return math.MaxInt
25 | }
26 | return maxNumUsers
27 | }
28 |
29 | func configureObservability(mux *httptrace.ServeMux, releaseVersion string) func() {
30 | // Profiler
31 | err := profiler.Start(
32 | profiler.WithService("hishtory-api"),
33 | profiler.WithVersion(releaseVersion),
34 | profiler.WithAPIKey(os.Getenv("DD_API_KEY")),
35 | profiler.WithUDS("/var/run/datadog/apm.socket"),
36 | profiler.WithProfileTypes(
37 | profiler.CPUProfile,
38 | profiler.HeapProfile,
39 | ),
40 | )
41 | if err != nil {
42 | fmt.Printf("Failed to start DataDog profiler: %v\n", err)
43 | }
44 | // Tracer
45 | tracer.Start(
46 | tracer.WithRuntimeMetrics(),
47 | tracer.WithService("hishtory-api"),
48 | tracer.WithUDS("/var/run/datadog/apm.socket"),
49 | )
50 |
51 | // Pprof
52 | mux.HandleFunc("/debug/pprof/", pprofhttp.Index)
53 | mux.HandleFunc("/debug/pprof/cmdline", pprofhttp.Cmdline)
54 | mux.HandleFunc("/debug/pprof/profile", pprofhttp.Profile)
55 | mux.HandleFunc("/debug/pprof/symbol", pprofhttp.Symbol)
56 | mux.HandleFunc("/debug/pprof/trace", pprofhttp.Trace)
57 |
58 | // Func to stop all of the above
59 | return func() {
60 | profiler.Stop()
61 | tracer.Stop()
62 | }
63 | }
64 |
65 | func getHishtoryVersion(r *http.Request) string {
66 | return r.Header.Get("X-Hishtory-Version")
67 | }
68 |
69 | func getRemoteAddr(r *http.Request) string {
70 | addr, ok := r.Header["X-Real-Ip"]
71 | if !ok || len(addr) == 0 {
72 | return r.RemoteAddr
73 | }
74 | return addr[0]
75 | }
76 |
77 | func getRequiredQueryParam(r *http.Request, queryParam string) string {
78 | val := r.URL.Query().Get(queryParam)
79 | if val == "" {
80 | panic(fmt.Sprintf("request to %s is missing required query param=%#v", r.URL, queryParam))
81 | }
82 | return val
83 | }
84 |
85 | func getOptionalQueryParam(r *http.Request, queryParam string, isRequiredInTestEnvironment bool) string {
86 | val := r.URL.Query().Get(queryParam)
87 | if val == "" && isRequiredInTestEnvironment {
88 | panic(fmt.Sprintf("request to %s is missing optional query param=%#v that is required in test environments", r.URL, queryParam))
89 | }
90 | return val
91 | }
92 |
93 | func checkGormError(err error) {
94 | if err == nil {
95 | return
96 | }
97 |
98 | _, filename, line, _ := runtime.Caller(1)
99 | panic(fmt.Sprintf("DB error at %s:%d: %v", filename, line, err))
100 | }
101 |
--------------------------------------------------------------------------------
/backend/web/caddy/Caddyfile:
--------------------------------------------------------------------------------
1 | hishtory.dev:80, localhost:80 {
2 | root /srv/landing
3 | gzip
4 | ext .html
5 | log stdout
6 | tls off
7 | }
8 |
--------------------------------------------------------------------------------
/backend/web/caddy/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM abiosoft/caddy
2 |
3 | LABEL "com.datadoghq.ad.logs"='[{"source": "caddy", "service": "web"}]'
4 |
5 | COPY backend/web/caddy/Caddyfile /etc/
6 | COPY backend/web/landing/www/ /srv/landing
7 |
--------------------------------------------------------------------------------
/backend/web/landing/www/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | bower_components
--------------------------------------------------------------------------------
/backend/web/landing/www/img/aidemo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddworken/hishtory/0e89432849b257aba3c0383f7264d5dbfe7a68a2/backend/web/landing/www/img/aidemo.png
--------------------------------------------------------------------------------
/backend/web/landing/www/img/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddworken/hishtory/0e89432849b257aba3c0383f7264d5dbfe7a68a2/backend/web/landing/www/img/demo.gif
--------------------------------------------------------------------------------
/backend/web/landing/www/img/webui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddworken/hishtory/0e89432849b257aba3c0383f7264d5dbfe7a68a2/backend/web/landing/www/img/webui.png
--------------------------------------------------------------------------------
/backend/web/landing/www/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | See here.
8 |
9 |
10 |
--------------------------------------------------------------------------------
/backend/web/landing/www/install.py:
--------------------------------------------------------------------------------
1 | """
2 | A small install script to download the correct hishtory binary for the current OS/architecture.
3 | The hishtory binary is in charge of installing itself, this just downloads the correct binary and
4 | executes it.
5 | """
6 |
7 | import json
8 | import urllib.request
9 | import platform
10 | import sys
11 | import os
12 |
13 | def get_executable_tmpdir():
14 | specified_dir = os.environ.get('TMPDIR', '')
15 | if specified_dir:
16 | return specified_dir
17 | try:
18 | if hasattr(os, 'ST_NOEXEC'):
19 | if os.statvfs("/tmp").f_flag & os.ST_NOEXEC:
20 | # /tmp/ is mounted as NOEXEC, so fall back to the current working directory
21 | return os.getcwd()
22 | except:
23 | pass
24 | return "/tmp/"
25 |
26 | with urllib.request.urlopen('https://api.hishtory.dev/api/v1/download') as response:
27 | resp_body = response.read()
28 | download_options = json.loads(resp_body)
29 |
30 | if platform.system() == 'Linux' and platform.machine() == "x86_64":
31 | download_url = download_options['linux_amd_64_url']
32 | elif platform.system() == 'Linux' and platform.machine() == "aarch64":
33 | download_url = download_options['linux_arm_64_url']
34 | elif platform.system() == 'Linux' and platform.machine() == "armv7l":
35 | download_url = download_options['linux_arm_7_url']
36 | elif platform.system() == 'Darwin' and platform.machine() == 'arm64':
37 | download_url = download_options['darwin_arm_64_url']
38 | elif platform.system() == 'Darwin' and platform.machine() == 'x86_64':
39 | download_url = download_options['darwin_amd_64_url']
40 | else:
41 | print(f"No hishtory binary for system={platform.system()}, machine={platform.machine()}!\nIf you believe this is a mistake, please open an issue here: https://github.com/ddworken/hishtory/issues")
42 | sys.exit(1)
43 |
44 | with urllib.request.urlopen(download_url) as response:
45 | hishtory_binary = response.read()
46 |
47 | tmpFilePath = os.path.join(get_executable_tmpdir(), 'hishtory-client')
48 | if os.path.exists(tmpFilePath):
49 | os.remove(tmpFilePath)
50 | with open(tmpFilePath, 'wb') as f:
51 | f.write(hishtory_binary)
52 | os.system('chmod +x ' + tmpFilePath)
53 | cmd = tmpFilePath + ' install'
54 | if os.environ.get('HISHTORY_OFFLINE'):
55 | cmd += " --offline"
56 | additional_flags = [flag for flag in sys.argv[1:] if flag.startswith("-") and flag != "-" and flag != "--"]
57 | if additional_flags:
58 | cmd += " " + " ".join(additional_flags)
59 | exitCode = os.system(cmd)
60 | os.remove(tmpFilePath)
61 | if exitCode != 0:
62 | raise Exception("failed to install downloaded hishtory client via `" + tmpFilePath +" install` (is that directory mounted noexec? Consider setting an alternate directory via the TMPDIR environment variable)!")
63 | print('Succesfully installed hishtory! Open a new terminal, try running a command, and then running `hishtory query`.')
64 |
--------------------------------------------------------------------------------
/client/cmd/configAdd.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "strings"
7 |
8 | "github.com/ddworken/hishtory/client/hctx"
9 | "github.com/ddworken/hishtory/client/lib"
10 |
11 | "github.com/spf13/cobra"
12 | )
13 |
14 | var configAddCmd = &cobra.Command{
15 | Use: "config-add",
16 | Short: "Add a config option",
17 | GroupID: GROUP_ID_CONFIG,
18 | Run: func(cmd *cobra.Command, args []string) {
19 | lib.CheckFatalError(cmd.Help())
20 | os.Exit(1)
21 | },
22 | }
23 |
24 | var addCustomColumnsCmd = &cobra.Command{
25 | Use: "custom-columns",
26 | Aliases: []string{"custom-column"},
27 | Short: "Add a custom column",
28 | Args: cobra.ExactArgs(2),
29 | Run: func(cmd *cobra.Command, args []string) {
30 | columnName := args[0]
31 | command := args[1]
32 | ctx := hctx.MakeContext()
33 | config := hctx.GetConf(ctx)
34 | if config.CustomColumns == nil {
35 | config.CustomColumns = make([]hctx.CustomColumnDefinition, 0)
36 | }
37 | for _, existingColumn := range config.CustomColumns {
38 | if strings.EqualFold(existingColumn.ColumnName, columnName) {
39 | lib.CheckFatalError(fmt.Errorf("cannot create a column named %#v since there is already one named %#v", existingColumn.ColumnName, columnName))
40 | }
41 | }
42 | config.CustomColumns = append(config.CustomColumns, hctx.CustomColumnDefinition{ColumnName: columnName, ColumnCommand: command})
43 | lib.CheckFatalError(hctx.SetConfig(config))
44 | },
45 | }
46 |
47 | var addDisplayedColumnsCmd = &cobra.Command{
48 | Use: "displayed-columns",
49 | Aliases: []string{"displayed-column"},
50 | Short: "Add a column to be displayed",
51 | Args: cobra.ExactArgs(1),
52 | Run: func(cmd *cobra.Command, args []string) {
53 | ctx := hctx.MakeContext()
54 | config := hctx.GetConf(ctx)
55 | config.DisplayedColumns = append(config.DisplayedColumns, args...)
56 | lib.CheckFatalError(hctx.SetConfig(config))
57 | },
58 | }
59 |
60 | var addDefaultSearchColumnsCmd = &cobra.Command{
61 | Use: "default-search-columns",
62 | Aliases: []string{"default-search-column"},
63 | Short: "Add a column that is used for \"default\" search queries that don't use any search atoms",
64 | Long: "By default hishtory queries are checked against `command`, `current_working_directory`, and `hostname`. This option can be used to add additional columns to the list of columns checked in default queries. E.g. to add a custom column named `git_remote` to the list of default search columns, you would run `hishtory config-add default-search-columns git_remote`",
65 | Args: cobra.ExactArgs(1),
66 | Run: func(cmd *cobra.Command, args []string) {
67 | ctx := hctx.MakeContext()
68 | config := hctx.GetConf(ctx)
69 | lib.CheckFatalError(validateDefaultSearchColumns(ctx, args))
70 | config.DefaultSearchColumns = append(config.DefaultSearchColumns, args...)
71 | lib.CheckFatalError(hctx.SetConfig(config))
72 | },
73 | }
74 |
75 | func init() {
76 | rootCmd.AddCommand(configAddCmd)
77 | configAddCmd.AddCommand(addCustomColumnsCmd)
78 | configAddCmd.AddCommand(addDisplayedColumnsCmd)
79 | configAddCmd.AddCommand(addDefaultSearchColumnsCmd)
80 | }
81 |
--------------------------------------------------------------------------------
/client/cmd/enableDisable.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/ddworken/hishtory/client/hctx"
7 | "github.com/ddworken/hishtory/client/lib"
8 |
9 | "github.com/spf13/cobra"
10 | )
11 |
12 | var enableCmd = &cobra.Command{
13 | Use: "enable",
14 | Short: "Enable hiSHtory recording",
15 | GroupID: GROUP_ID_CONFIG,
16 | Run: func(cmd *cobra.Command, args []string) {
17 | ctx := hctx.MakeContext()
18 | lib.CheckFatalError(Enable(ctx))
19 | },
20 | }
21 |
22 | var disableCmd = &cobra.Command{
23 | Use: "disable",
24 | Short: "Disable hiSHtory recording",
25 | GroupID: GROUP_ID_CONFIG,
26 | Run: func(cmd *cobra.Command, args []string) {
27 | ctx := hctx.MakeContext()
28 | lib.CheckFatalError(Disable(ctx))
29 | },
30 | }
31 |
32 | func Enable(ctx context.Context) error {
33 | config := hctx.GetConf(ctx)
34 | config.IsEnabled = true
35 | return hctx.SetConfig(config)
36 | }
37 |
38 | func Disable(ctx context.Context) error {
39 | config := hctx.GetConf(ctx)
40 | config.IsEnabled = false
41 | return hctx.SetConfig(config)
42 | }
43 |
44 | func init() {
45 | rootCmd.AddCommand(enableCmd)
46 | rootCmd.AddCommand(disableCmd)
47 | }
48 |
--------------------------------------------------------------------------------
/client/cmd/export.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 | "fmt"
7 | "io"
8 | "os"
9 |
10 | "github.com/ddworken/hishtory/client/data"
11 | "github.com/ddworken/hishtory/client/hctx"
12 | "github.com/ddworken/hishtory/client/lib"
13 |
14 | "github.com/spf13/cobra"
15 | )
16 |
17 | var exportJsonCmd = &cobra.Command{
18 | Use: "export-json",
19 | Short: "Export history entries formatted in JSON lines format (as accepted by hishtory import-json, and easily parsable by other tools)",
20 | GroupID: GROUP_ID_MANAGEMENT,
21 | Run: func(cmd *cobra.Command, args []string) {
22 | ctx := hctx.MakeContext()
23 | err := exportToJson(ctx, os.Stdout)
24 | lib.CheckFatalError(err)
25 | },
26 | }
27 |
28 | func structToMap(entry data.HistoryEntry) (map[string]interface{}, error) {
29 | inrec, err := json.Marshal(entry)
30 | if err != nil {
31 | return nil, err
32 | }
33 | var m map[string]interface{}
34 | err = json.Unmarshal(inrec, &m)
35 | return m, err
36 | }
37 |
38 | func exportToJson(ctx context.Context, w io.Writer) error {
39 | db := hctx.GetDb(ctx)
40 | chunkSize := 1000
41 | offset := 0
42 | for {
43 | entries, err := lib.SearchWithOffset(ctx, db, "", chunkSize, offset)
44 | if err != nil {
45 | return fmt.Errorf("failed to search for history entries with offset=%d: %w", offset, err)
46 | }
47 | if len(entries) == 0 {
48 | break
49 | }
50 | for _, entry := range entries {
51 | if entry.Command == "" {
52 | // Skip empty commands, see https://github.com/ddworken/hishtory/issues/279
53 | continue
54 | }
55 | m, err := structToMap(*entry)
56 | if err != nil {
57 | return err
58 | }
59 | delete(m, "device_id")
60 | delete(m, "entry_id")
61 | j, err := json.Marshal(m)
62 | if err != nil {
63 | return err
64 | }
65 | _, err = w.Write(j)
66 | if err != nil {
67 | return err
68 | }
69 | _, err = w.Write([]byte("\n"))
70 | if err != nil {
71 | return err
72 | }
73 | }
74 | offset += chunkSize
75 | }
76 | return nil
77 | }
78 |
79 | func init() {
80 | rootCmd.AddCommand(exportJsonCmd)
81 | }
82 |
--------------------------------------------------------------------------------
/client/cmd/install_test.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "os"
5 | "path"
6 | "testing"
7 |
8 | "github.com/ddworken/hishtory/client/data"
9 | "github.com/ddworken/hishtory/client/hctx"
10 | "github.com/ddworken/hishtory/shared/testutils"
11 |
12 | "github.com/stretchr/testify/require"
13 | )
14 |
15 | func TestSetup(t *testing.T) {
16 | defer testutils.BackupAndRestore(t)()
17 | defer testutils.RunTestServer()()
18 |
19 | homedir, err := os.UserHomeDir()
20 | require.NoError(t, err)
21 | if _, err := os.Stat(path.Join(homedir, data.GetHishtoryPath(), data.CONFIG_PATH)); err == nil {
22 | t.Fatalf("hishtory secret file already exists!")
23 | }
24 | require.NoError(t, setup("", false))
25 | if _, err := os.Stat(path.Join(homedir, data.GetHishtoryPath(), data.CONFIG_PATH)); err != nil {
26 | t.Fatalf("hishtory secret file does not exist after Setup()!")
27 | }
28 | data, err := os.ReadFile(path.Join(homedir, data.GetHishtoryPath(), data.CONFIG_PATH))
29 | require.NoError(t, err)
30 | if len(data) < 10 {
31 | t.Fatalf("hishtory secret has unexpected length: %d", len(data))
32 | }
33 | config := hctx.GetConf(hctx.MakeContext())
34 | if config.IsOffline != false {
35 | t.Fatalf("hishtory config should have been offline")
36 | }
37 | }
38 |
39 | func TestSetupOffline(t *testing.T) {
40 | defer testutils.BackupAndRestore(t)()
41 | defer testutils.RunTestServer()()
42 |
43 | homedir, err := os.UserHomeDir()
44 | require.NoError(t, err)
45 | if _, err := os.Stat(path.Join(homedir, data.GetHishtoryPath(), data.CONFIG_PATH)); err == nil {
46 | t.Fatalf("hishtory secret file already exists!")
47 | }
48 | require.NoError(t, setup("", true))
49 | if _, err := os.Stat(path.Join(homedir, data.GetHishtoryPath(), data.CONFIG_PATH)); err != nil {
50 | t.Fatalf("hishtory secret file does not exist after Setup()!")
51 | }
52 | data, err := os.ReadFile(path.Join(homedir, data.GetHishtoryPath(), data.CONFIG_PATH))
53 | require.NoError(t, err)
54 | if len(data) < 10 {
55 | t.Fatalf("hishtory secret has unexpected length: %d", len(data))
56 | }
57 | config := hctx.GetConf(hctx.MakeContext())
58 | if config.IsOffline != true {
59 | t.Fatalf("hishtory config should have been offline, actual=%#v", string(data))
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/client/cmd/reupload.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "github.com/ddworken/hishtory/client/hctx"
5 | "github.com/ddworken/hishtory/client/lib"
6 |
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | var reuploadCmd = &cobra.Command{
11 | Use: "reupload",
12 | Hidden: true,
13 | Short: "[Debug Only] Reupload your entire hiSHtory to all other devices",
14 | Run: func(cmd *cobra.Command, args []string) {
15 | lib.CheckFatalError(lib.Reupload(hctx.MakeContext()))
16 | },
17 | }
18 |
19 | func init() {
20 | rootCmd.AddCommand(reuploadCmd)
21 | }
22 |
--------------------------------------------------------------------------------
/client/cmd/root.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 2022 NAME HERE
3 | */
4 | package cmd
5 |
6 | import (
7 | "os"
8 |
9 | "github.com/ddworken/hishtory/client/lib"
10 |
11 | "github.com/spf13/cobra"
12 | )
13 |
14 | // rootCmd represents the base command when called without any subcommands
15 | var rootCmd = &cobra.Command{
16 | Use: "hishtory",
17 | Short: "hiSHtory: Better shell history",
18 | }
19 |
20 | // Execute adds all child commands to the root command and sets flags appropriately.
21 | // This is called by main.main(). It only needs to happen once to the rootCmd.
22 | func Execute() {
23 | err := rootCmd.Execute()
24 | if err != nil {
25 | os.Exit(1)
26 | }
27 | }
28 |
29 | func init() {
30 | rootCmd.AddGroup(&cobra.Group{ID: GROUP_ID_QUERYING, Title: "History Searching"})
31 | rootCmd.AddGroup(&cobra.Group{ID: GROUP_ID_MANAGEMENT, Title: "History Management"})
32 | rootCmd.AddGroup(&cobra.Group{ID: GROUP_ID_CONFIG, Title: "Configuration"})
33 | rootCmd.AddGroup(&cobra.Group{ID: GROUP_ID_INSTALL, Title: "Installation"})
34 | rootCmd.Version = "v0." + lib.Version
35 | }
36 |
--------------------------------------------------------------------------------
/client/cmd/status.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 |
7 | "github.com/ddworken/hishtory/client/data"
8 | "github.com/ddworken/hishtory/client/hctx"
9 | "github.com/ddworken/hishtory/client/lib"
10 |
11 | "github.com/spf13/cobra"
12 | "gopkg.in/yaml.v3"
13 | )
14 |
15 | var (
16 | verbose *bool
17 | configFlag *bool
18 | )
19 |
20 | var statusCmd = &cobra.Command{
21 | Use: "status",
22 | Short: "View status info including the secret key which is needed to sync shell history from another machine",
23 | Run: func(cmd *cobra.Command, args []string) {
24 | ctx := hctx.MakeContext()
25 | config := hctx.GetConf(ctx)
26 | fmt.Printf("hiSHtory: v0.%s\nEnabled: %v\n", lib.Version, config.IsEnabled)
27 | fmt.Printf("Secret Key: %s\n", config.UserSecret)
28 | if *verbose {
29 | fmt.Printf("User ID: %s\n", data.UserId(config.UserSecret))
30 | fmt.Printf("Device ID: %s\n", config.DeviceId)
31 | printOnlineStatus(config)
32 | }
33 | fmt.Printf("Commit Hash: %s\n", lib.GitCommit)
34 | if *configFlag {
35 | y, err := yaml.Marshal(config)
36 | if err != nil {
37 | lib.CheckFatalError(fmt.Errorf("failed to marshal config to yaml: %w", err))
38 | }
39 | indented := "\t" + strings.ReplaceAll(string(y), "\n", "\n\t")
40 | fmt.Printf("Full Config:\n%s\n", indented)
41 | }
42 | },
43 | }
44 |
45 | func printOnlineStatus(config *hctx.ClientConfig) {
46 | if config.IsOffline {
47 | fmt.Println("Sync Mode: Disabled")
48 | } else {
49 | fmt.Println("Sync Mode: Enabled")
50 | if lib.GetServerHostname() != lib.DefaultServerHostname {
51 | fmt.Println("Sync Server: " + lib.GetServerHostname())
52 | }
53 | if config.HaveMissedUploads || len(config.PendingDeletionRequests) > 0 {
54 | fmt.Println("Sync Status: Unsynced (device is offline?)")
55 | fmt.Printf(" HaveMissedUploads=%v MissedUploadTimestamp=%v len(PendingDeletionRequests)=%v\n", config.HaveMissedUploads, config.MissedUploadTimestamp, len(config.PendingDeletionRequests))
56 | } else {
57 | fmt.Println("Sync Status: Synced")
58 | }
59 | }
60 | }
61 |
62 | func init() {
63 | rootCmd.AddCommand(statusCmd)
64 | verbose = statusCmd.Flags().BoolP("verbose", "v", false, "Display verbose hiSHtory information")
65 | configFlag = statusCmd.Flags().Bool("full-config", false, "Display hiSHtory's full config")
66 | }
67 |
--------------------------------------------------------------------------------
/client/cmd/syncing.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | "github.com/ddworken/hishtory/client/data"
8 | "github.com/ddworken/hishtory/client/hctx"
9 | "github.com/ddworken/hishtory/client/lib"
10 |
11 | "github.com/spf13/cobra"
12 | )
13 |
14 | var syncingCmd = &cobra.Command{
15 | Use: "syncing",
16 | Short: "Configure syncing to enable or disable syncing with the hishtory backend",
17 | Long: "Run `hishtory syncing disable` to disable syncing and `hishtory syncing enable` to enable syncing.",
18 | ValidArgs: []string{"disable", "enable"},
19 | Args: cobra.MatchAll(cobra.OnlyValidArgs, cobra.ExactArgs(1)),
20 | Run: func(cmd *cobra.Command, args []string) {
21 | syncingStatus := false
22 | if args[0] == "disable" {
23 | syncingStatus = false
24 | } else if args[0] == "enable" {
25 | syncingStatus = true
26 | } else {
27 | lib.CheckFatalError(fmt.Errorf("unexpected syncing argument %q", args[0]))
28 | }
29 |
30 | ctx := hctx.MakeContext()
31 | conf := hctx.GetConf(ctx)
32 | if syncingStatus {
33 | if conf.IsOffline {
34 | lib.CheckFatalError(switchToOnline(ctx))
35 | fmt.Println("Enabled syncing successfully")
36 | } else {
37 | lib.CheckFatalError(fmt.Errorf("device is already online"))
38 | }
39 | } else {
40 | if conf.IsOffline {
41 | lib.CheckFatalError(fmt.Errorf("device is already offline"))
42 | } else {
43 | lib.CheckFatalError(switchToOffline(ctx))
44 | fmt.Println("Disabled syncing successfully")
45 | }
46 | }
47 | },
48 | }
49 |
50 | func switchToOnline(ctx context.Context) error {
51 | config := hctx.GetConf(ctx)
52 | config.IsOffline = false
53 | err := hctx.SetConfig(config)
54 | if err != nil {
55 | return fmt.Errorf("failed to switch device to online due to error while setting config: %w", err)
56 | }
57 | err = registerAndBootstrapDevice(ctx, config, hctx.GetDb(ctx), config.UserSecret)
58 | if err != nil {
59 | return fmt.Errorf("failed to register device with backend: %w", err)
60 | }
61 | err = lib.Reupload(ctx)
62 | if err != nil {
63 | return fmt.Errorf("failed to switch device to online due to error while uploading history entries: %w", err)
64 | }
65 | return nil
66 | }
67 |
68 | func switchToOffline(ctx context.Context) error {
69 | config := hctx.GetConf(ctx)
70 | config.IsOffline = true
71 | err := hctx.SetConfig(config)
72 | if err != nil {
73 | return fmt.Errorf("failed to switch device to offline due to error while setting config: %w", err)
74 | }
75 | _, err = lib.ApiPost(ctx, "/api/v1/uninstall?user_id="+data.UserId(hctx.GetConf(ctx).UserSecret)+"&device_id="+hctx.GetConf(ctx).DeviceId, "application/json", []byte{})
76 | if err != nil {
77 | return fmt.Errorf("failed to switch device to offline due to error while deleting sync state: %w", err)
78 | }
79 | return nil
80 | }
81 |
82 | func init() {
83 | rootCmd.AddCommand(syncingCmd)
84 | }
85 |
--------------------------------------------------------------------------------
/client/cmd/webui.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "strings"
7 |
8 | "github.com/ddworken/hishtory/client/hctx"
9 | "github.com/ddworken/hishtory/client/lib"
10 | "github.com/ddworken/hishtory/client/webui"
11 |
12 | "github.com/spf13/cobra"
13 | )
14 |
15 | var (
16 | disableAuth *bool
17 | forceCreds *string
18 | port *int
19 | )
20 |
21 | var webUiCmd = &cobra.Command{
22 | Use: "start-web-ui",
23 | Short: "Serve a basic web UI for interacting with your shell history",
24 | Run: func(cmd *cobra.Command, args []string) {
25 | overridenUsername := ""
26 | overridenPassword := ""
27 | if *forceCreds != "" {
28 | if strings.Contains(*forceCreds, ":") {
29 | splitCreds := strings.SplitN(*forceCreds, ":", 2)
30 | overridenUsername = splitCreds[0]
31 | overridenPassword = splitCreds[1]
32 | } else {
33 | lib.CheckFatalError(fmt.Errorf("--force-creds=%#v doesn't contain a colon to delimit username and password", *forceCreds))
34 | }
35 | }
36 | if *disableAuth && *forceCreds != "" {
37 | lib.CheckFatalError(fmt.Errorf("cannot specify both --disable-auth and --force-creds"))
38 | }
39 | lib.CheckFatalError(webui.StartWebUiServer(hctx.MakeContext(), *port, *disableAuth, overridenUsername, overridenPassword))
40 | os.Exit(1)
41 | },
42 | }
43 |
44 | func init() {
45 | rootCmd.AddCommand(webUiCmd)
46 | disableAuth = webUiCmd.Flags().Bool("disable-auth", false, "Disable authentication for the Web UI (Warning: This means your entire shell history will be accessible from the local web server)")
47 | forceCreds = webUiCmd.Flags().String("force-creds", "", "Specify the credentials to use for basic auth in the form `user:password`")
48 | port = webUiCmd.Flags().Int("port", 8000, "The port for the web server to listen on")
49 | }
50 |
--------------------------------------------------------------------------------
/client/data/data_test.go:
--------------------------------------------------------------------------------
1 | package data
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestEncryptDecrypt(t *testing.T) {
8 | k1 := EncryptionKey("key")
9 | k2 := EncryptionKey("key")
10 | if string(k1) != string(k2) {
11 | t.Fatalf("Expected EncryptionKey to be deterministic!")
12 | }
13 |
14 | ciphertext, nonce, err := Encrypt("key", []byte("hello world!"), []byte("extra"))
15 | checkError(t, err)
16 | plaintext, err := Decrypt("key", ciphertext, []byte("extra"), nonce)
17 | checkError(t, err)
18 | if string(plaintext) != "hello world!" {
19 | t.Fatalf("Expected decrypt(encrypt(x)) to work, but it didn't!")
20 | }
21 | }
22 |
23 | func checkError(t *testing.T, err error) {
24 | if err != nil {
25 | t.Fatal(err)
26 | }
27 | }
28 |
29 | func TestCustomColumnSerialization(t *testing.T) {
30 | cc1 := CustomColumn{
31 | Name: "name1",
32 | Val: "val1",
33 | }
34 | cc2 := CustomColumn{
35 | Name: "name2",
36 | Val: "val2",
37 | }
38 | var ccs CustomColumns = make(CustomColumns, 0)
39 |
40 | // Empty array
41 | v, err := ccs.Value()
42 | if err != nil {
43 | t.Fatalf("unexpected err: %v", err)
44 | }
45 | val := string(v.([]uint8))
46 | if val != "[]" {
47 | t.Fatalf("unexpected val for empty CustomColumns: %#v", val)
48 | }
49 |
50 | // Non-empty array
51 | ccs = append(ccs, cc1, cc2)
52 | v, err = ccs.Value()
53 | if err != nil {
54 | t.Fatalf("unexpected err: %v", err)
55 | }
56 | val = string(v.([]uint8))
57 | if val != "[{\"name\":\"name1\",\"value\":\"val1\"},{\"name\":\"name2\",\"value\":\"val2\"}]" {
58 | t.Fatalf("unexpected val for empty CustomColumns: %#v", val)
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/client/lib/config.fish:
--------------------------------------------------------------------------------
1 | # For detecting color rendering support for this terminal, see #134
2 | hishtory getColorSupport
3 | export _hishtory_tui_color=$status
4 |
5 | function _hishtory_post_exec --on-event fish_preexec
6 | # Runs after , but before the command is executed
7 | set --global _hishtory_command $argv
8 | set --global _hishtory_start_time (hishtory getTimestamp)
9 | hishtory presaveHistoryEntry fish "$_hishtory_command" $_hishtory_start_time 2>&1 >/dev/null &; disown # Background Run
10 | # hishtory presaveHistoryEntry fish "$_hishtory_command" $_hishtory_start_time 2>&1 >/dev/null # Foreground Run
11 | end
12 |
13 | set --global _hishtory_first_prompt 1
14 |
15 | function __hishtory_on_prompt --on-event fish_prompt
16 | # Runs after the command is executed in order to render the prompt
17 | # $? contains the exit code
18 | set _hishtory_exit_code $status
19 | if [ -n "$_hishtory_first_prompt" ]
20 | set --global -e _hishtory_first_prompt
21 | else if [ -n "$_hishtory_command" ]
22 | hishtory saveHistoryEntry fish $_hishtory_exit_code "$_hishtory_command" $_hishtory_start_time 2>&1 >/dev/null &; disown # Background Run
23 | # hishtory saveHistoryEntry fish $_hishtory_exit_code "$_hishtory_command" $_hishtory_start_time 2>&1 >/dev/null # Foreground Run
24 | hishtory updateLocalDbFromRemote 2>&1 >/dev/null &; disown
25 | set --global -e _hishtory_command # Unset _hishtory_command so we don't double-save entries when fish_prompt is invoked but fish_postexec isn't
26 | end
27 | end
28 |
29 | function __hishtory_on_control_r
30 | set -l tmp (mktemp -t fish.XXXXXX)
31 | set -x init_query (commandline -b)
32 | HISHTORY_TERM_INTEGRATION=1 HISHTORY_SHELL_NAME=fish hishtory tquery $init_query > $tmp
33 | set -l res $status
34 | commandline -f repaint
35 | if [ -s $tmp ]
36 | commandline -r -- (cat $tmp)
37 | end
38 | rm -f $tmp
39 | end
40 |
41 | [ (hishtory config-get enable-control-r) = true ] && bind \cr __hishtory_on_control_r
42 |
43 | hishtory completion fish | source
--------------------------------------------------------------------------------
/client/lib/config.zsh:
--------------------------------------------------------------------------------
1 | autoload -U add-zsh-hook
2 | add-zsh-hook zshaddhistory _hishtory_add
3 | add-zsh-hook precmd _hishtory_precmd
4 |
5 | _hishtory_first_prompt=1
6 |
7 | # For detecting color rendering support for this terminal, see #134
8 | hishtory getColorSupport
9 | export _hishtory_tui_color=$?
10 |
11 | function _hishtory_add() {
12 | # Runs after , but before the command is executed
13 | # $1 contains the command that was run
14 | _hishtory_command=$1
15 | _hishtory_start_time=`hishtory getTimestamp`
16 | if ! [ -z "$_hishtory_command " ]; then
17 | (hishtory presaveHistoryEntry zsh "$_hishtory_command" $_hishtory_start_time &) 2>&1 >/dev/null # Background Run
18 | # hishtory presaveHistoryEntry zsh "$_hishtory_command" $_hishtory_start_time 2>&1 >/dev/null # Foreground Run
19 | fi
20 | }
21 |
22 | function _hishtory_precmd() {
23 | # Runs after the command is executed in order to render the prompt
24 | # $? contains the exit code
25 | _hishtory_exit_code=$?
26 | if [ -n "${_hishtory_first_prompt:-}" ]; then
27 | unset _hishtory_first_prompt
28 | return
29 | fi
30 | (hishtory saveHistoryEntry zsh $_hishtory_exit_code "$_hishtory_command" $_hishtory_start_time &) 2>&1 >/dev/null # Background Run
31 | # hishtory saveHistoryEntry zsh $_hishtory_exit_code "$_hishtory_command" $_hishtory_start_time 2>&1 >/dev/null # Foreground Run
32 | (hishtory updateLocalDbFromRemote &) 2>&1 >/dev/null
33 | }
34 |
35 | _hishtory_widget() {
36 | BUFFER=$(HISHTORY_TERM_INTEGRATION=1 HISHTORY_SHELL_NAME=zsh hishtory tquery $BUFFER)
37 | CURSOR=${#BUFFER}
38 | zle reset-prompt
39 | }
40 |
41 | _hishtory_bind_control_r() {
42 | zle -N _hishtory_widget
43 | bindkey '^R' _hishtory_widget
44 | }
45 |
46 | [ "$(hishtory config-get enable-control-r)" = true ] && _hishtory_bind_control_r
47 |
48 | # If running in a test environment, force loading of compinit so that shell completions work.
49 | # Otherwise, we respect the user's choice and only run compdef if the user has loaded compinit.
50 | if [ -n "${HISHTORY_TEST:-}" ]; then
51 | autoload -Uz compinit
52 | compinit
53 | fi
54 |
55 | source <(hishtory completion zsh); which compdef >/dev/null 2>&1 && compdef _hishtory hishtory || true
--------------------------------------------------------------------------------
/client/lib/net.go:
--------------------------------------------------------------------------------
1 | //go:build !offline
2 | // +build !offline
3 |
4 | package lib
5 |
6 | import (
7 | "net/http"
8 | )
9 |
10 | func GetHttpClient() *http.Client {
11 | return http.DefaultClient
12 | }
13 |
14 | func IsOfflineBinary() bool {
15 | return false
16 | }
17 |
--------------------------------------------------------------------------------
/client/lib/net_disabled.go:
--------------------------------------------------------------------------------
1 | //go:build offline
2 | // +build offline
3 |
4 | package lib
5 |
6 | import "net/http"
7 |
8 | func GetHttpClient() *http.Client {
9 | panic("Cannot GetHttpClient() from a hishtory client compiled with the offline tag!")
10 | }
11 |
12 | func IsOfflineBinary() bool {
13 | return true
14 | }
15 |
--------------------------------------------------------------------------------
/client/lib/slsa_test.go:
--------------------------------------------------------------------------------
1 | package lib
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 | )
8 |
9 | func TestCheckForDowngrade(t *testing.T) {
10 | require.NoError(t, checkForDowngrade("v0.100", "v0.100"))
11 | require.NoError(t, checkForDowngrade("v0.100", "v0.101"))
12 | require.NoError(t, checkForDowngrade("v0.100", "v0.200"))
13 | require.NoError(t, checkForDowngrade("v0.100", "v1.0"))
14 | require.NoError(t, checkForDowngrade("v0.1", "v1.0"))
15 | require.NoError(t, checkForDowngrade("v1.0", "v1.1"))
16 | require.Equal(t, "failed to update because the new version (\"v0.99\") is a downgrade compared to the current version (\"v0.100\")",
17 | checkForDowngrade("v0.100", "v0.99").Error())
18 | require.Equal(t, "failed to update because the new version (\"v0.10\") is a downgrade compared to the current version (\"v0.100\")",
19 | checkForDowngrade("v0.100", "v0.10").Error())
20 | require.Equal(t, "failed to update because the new version (\"v0.100\") is a downgrade compared to the current version (\"v1.0\")",
21 | checkForDowngrade("v1.0", "v0.100").Error())
22 | }
23 |
--------------------------------------------------------------------------------
/client/table/table_test.go:
--------------------------------------------------------------------------------
1 | // Forked from https://github.com/charmbracelet/bubbles/blob/master/table/table_test.go to add horizontal scrolling
2 |
3 | package table
4 |
5 | import (
6 | "testing"
7 |
8 | "github.com/ddworken/hishtory/shared/testutils"
9 | )
10 |
11 | func TestFromValues(t *testing.T) {
12 | input := "foo1,bar1\nfoo2,bar2\nfoo3,bar3"
13 | table := New(WithColumns([]Column{{Title: "Foo"}, {Title: "Bar"}}))
14 | table.FromValues(input, ",")
15 |
16 | if len(table.rows) != 3 {
17 | t.Fatalf("expect table to have 3 rows but it has %d", len(table.rows))
18 | }
19 |
20 | expect := []Row{
21 | {"foo1", "bar1"},
22 | {"foo2", "bar2"},
23 | {"foo3", "bar3"},
24 | }
25 | if !deepEqual(table.rows, expect) {
26 | t.Fatal("table rows is not equals to the input")
27 | }
28 | }
29 |
30 | func TestFromValuesWithTabSeparator(t *testing.T) {
31 | input := "foo1.\tbar1\nfoo,bar,baz\tbar,2"
32 | table := New(WithColumns([]Column{{Title: "Foo"}, {Title: "Bar"}}))
33 | table.FromValues(input, "\t")
34 |
35 | if len(table.rows) != 2 {
36 | t.Fatalf("expect table to have 2 rows but it has %d", len(table.rows))
37 | }
38 |
39 | expect := []Row{
40 | {"foo1.", "bar1"},
41 | {"foo,bar,baz", "bar,2"},
42 | }
43 | if !deepEqual(table.rows, expect) {
44 | t.Fatal("table rows is not equals to the input")
45 | }
46 | }
47 |
48 | func TestHScoll(t *testing.T) {
49 | table := New(
50 | WithColumns([]Column{{Title: "Column1", Width: 10}, {Title: "Column2", Width: 20}}),
51 | WithRows([]Row{
52 | {"a1", "a2345"},
53 | {"b1", "b23"},
54 | {"c1", "c1234567890abcdefghijklmnopqrstuvwxyz"},
55 | }),
56 | )
57 | testutils.CompareGoldens(t, table.View(), "unittestTable-truncatedTable")
58 | table.MoveRight(1)
59 | testutils.CompareGoldens(t, table.View(), "unittestTable-truncatedTable-right1")
60 | table.MoveRight(1)
61 | testutils.CompareGoldens(t, table.View(), "unittestTable-truncatedTable-right2")
62 | table.MoveRight(1)
63 | testutils.CompareGoldens(t, table.View(), "unittestTable-truncatedTable-right3")
64 | table.MoveLeft(1)
65 | testutils.CompareGoldens(t, table.View(), "unittestTable-truncatedTable-right2")
66 | }
67 |
68 | func deepEqual(a, b []Row) bool {
69 | if len(a) != len(b) {
70 | return false
71 | }
72 | for i, r := range a {
73 | for j, f := range r {
74 | if f != b[i][j] {
75 | return false
76 | }
77 | }
78 | }
79 | return true
80 | }
81 |
--------------------------------------------------------------------------------
/client/testdata/TestBashOrderingBug-Export:
--------------------------------------------------------------------------------
1 | command1
2 | command2
3 | command3
4 | command4
5 |
--------------------------------------------------------------------------------
/client/testdata/TestChangeSyncingStatus-Offline:
--------------------------------------------------------------------------------
1 | hiSHtory: v0.Unknown
2 | Enabled: true
3 | Sync Mode: Disabled
4 | Commit Hash: Unknown
5 |
--------------------------------------------------------------------------------
/client/testdata/TestChangeSyncingStatus-Online:
--------------------------------------------------------------------------------
1 | hiSHtory: v0.Unknown
2 | Enabled: true
3 | Sync Mode: Enabled
4 | Sync Server: http://localhost:8080
5 | Sync Status: Synced
6 | Commit Hash: Unknown
7 |
--------------------------------------------------------------------------------
/client/testdata/TestDefaultSearchColumns-Default-Echo:
--------------------------------------------------------------------------------
1 | echo hi
2 | ls
3 |
--------------------------------------------------------------------------------
/client/testdata/TestDefaultSearchColumns-Default-Hi:
--------------------------------------------------------------------------------
1 | echo hi
2 | ls
3 |
--------------------------------------------------------------------------------
/client/testdata/TestDefaultSearchColumns-MyCol-bar:
--------------------------------------------------------------------------------
1 | ls
2 |
--------------------------------------------------------------------------------
/client/testdata/TestDefaultSearchColumns-MyCol-baz:
--------------------------------------------------------------------------------
1 | echo hi
2 |
--------------------------------------------------------------------------------
/client/testdata/TestDefaultSearchColumns-NoCWD-Echo:
--------------------------------------------------------------------------------
1 | echo hi
2 |
--------------------------------------------------------------------------------
/client/testdata/TestDefaultSearchColumns-NoCWD-Hi:
--------------------------------------------------------------------------------
1 | echo hi
2 | ls
3 |
--------------------------------------------------------------------------------
/client/testdata/TestDefaultSearchColumns-NoCWDHostname-Echo:
--------------------------------------------------------------------------------
1 | echo hi
2 |
--------------------------------------------------------------------------------
/client/testdata/TestDefaultSearchColumns-NoCWDHostname-Hi:
--------------------------------------------------------------------------------
1 | echo hi
2 |
--------------------------------------------------------------------------------
/client/testdata/TestExportJson:
--------------------------------------------------------------------------------
1 | {"command":"echo synth2","current_working_directory":"/tmp/","custom_columns":null,"end_time":"2022-10-18T04:43:24Z","exit_code":2,"home_directory":"/home/david/","hostname":"localhost","local_username":"david","start_time":"2022-10-18T04:43:21Z"}
2 | {"command":"echo synth1","current_working_directory":"/tmp/","custom_columns":[{"name":"MyCol","value":"bar"}],"end_time":"2022-10-18T04:43:19Z","exit_code":2,"home_directory":"/home/david/","hostname":"localhost","local_username":"david","start_time":"1970-01-14T22:56:07-08:00"}
3 |
--------------------------------------------------------------------------------
/client/testdata/TestFish-table:
--------------------------------------------------------------------------------
1 | CWD Hostname Exit Code Command
2 | / ghaction-runner-hostname 0 hishtory config-set displayed-columns CWD Hostname 'Exit Code' Command
3 | / ghaction-runner-hostname 0 exit
4 | / ghaction-runner-hostname 0 echo foo
5 | / ghaction-runner-hostname 0 fish
6 | / ghaction-runner-hostname 0 ls /tmp/ &
7 | / ghaction-runner-hostname 0 echo "foo"
8 | / ghaction-runner-hostname 0 echo bar
9 | / ghaction-runner-hostname 0 echo foo
10 |
--------------------------------------------------------------------------------
/client/testdata/TestInstallSkipConfigModification-InstallOutput-darwin:
--------------------------------------------------------------------------------
1 | Please edit "~/.bashrc" to add:
2 |
3 | ```
4 | # Hishtory Config:
5 | export PATH="$PATH:/Users/runner/.hishtory"
6 | source /Users/runner/.hishtory/config.sh
7 | ```
8 |
9 | Please edit "~/.bash_profile" to add:
10 |
11 | ```
12 | # Hishtory Config:
13 | export PATH="$PATH:/Users/runner/.hishtory"
14 | source /Users/runner/.hishtory/config.sh
15 | ```
16 |
17 | Please edit "~/.zshrc" to add:
18 |
19 | ```
20 | # Hishtory Config:
21 | export PATH="$PATH:/Users/runner/.hishtory"
22 | source /Users/runner/.hishtory/config.zsh
23 | ```
24 |
25 |
--------------------------------------------------------------------------------
/client/testdata/TestInstallSkipConfigModification-InstallOutput-linux:
--------------------------------------------------------------------------------
1 | Please edit "~/.bashrc" to add:
2 |
3 | ```
4 | # Hishtory Config:
5 | export PATH="$PATH:/home/runner/.hishtory"
6 | source /home/runner/.hishtory/config.sh
7 | ```
8 |
9 | Please edit "~/.bash_profile" to add:
10 |
11 | ```
12 | # Hishtory Config:
13 | export PATH="$PATH:/home/runner/.hishtory"
14 | source /home/runner/.hishtory/config.sh
15 | ```
16 |
17 | Please edit "~/.zshrc" to add:
18 |
19 | ```
20 | # Hishtory Config:
21 | export PATH="$PATH:/home/runner/.hishtory"
22 | source /home/runner/.hishtory/config.zsh
23 | ```
24 |
25 |
--------------------------------------------------------------------------------
/client/testdata/TestSortByConsistentTimezone-export:
--------------------------------------------------------------------------------
1 | first_entry
2 | second_entry
3 | third_entry
4 |
--------------------------------------------------------------------------------
/client/testdata/TestSortByConsistentTimezone-query:
--------------------------------------------------------------------------------
1 | Hostname CWD Timestamp Runtime Exit Code Command
2 | localhost /tmp/ Apr 16 2022 01:36:26 PDT 1s 2 third_entry
3 | localhost /tmp/ Apr 16 2022 01:19:46 PDT 1s 2 second_entry
4 | localhost /tmp/ Apr 16 2022 01:03:06 PDT 1s 2 first_entry
5 |
--------------------------------------------------------------------------------
/client/testdata/TestStatusFullConfig:
--------------------------------------------------------------------------------
1 | hiSHtory: v0.Unknown
2 | Enabled: true
3 | Commit Hash: Unknown
4 | Full Config:
5 | controlrsearchenabled: true
6 | displayedcolumns:
7 | - Hostname
8 | - CWD
9 | - Timestamp
10 | - Runtime
11 | - Exit Code
12 | - Command
13 | customcolumns: []
14 | forcecompactmode: false
15 | isoffline: false
16 | filterduplicatecommands: false
17 | timestampformat: Jan 2 2006 15:04:05 MST
18 | betamode: false
19 | highlightmatches: true
20 | aicompletion: true
21 | enablepresaving: true
22 | colorscheme:
23 | selectedtext: '#ffff99'
24 | selectedbackground: '#3300ff'
25 | bordercolor: '#585858'
26 | defaultfilter: ""
27 | aicompletionendpoint: https://api.openai.com/v1/chat/completions
28 | keybindings:
29 | up:
30 | - up
31 | - alt+OA
32 | - ctrl+p
33 | down:
34 | - down
35 | - alt+OB
36 | - ctrl+n
37 | pageup:
38 | - pgup
39 | pagedown:
40 | - pgdown
41 | selectentry:
42 | - enter
43 | selectentryandchangedir:
44 | - ctrl+x
45 | left:
46 | - left
47 | right:
48 | - right
49 | tableleft:
50 | - shift+left
51 | tableright:
52 | - shift+right
53 | deleteentry:
54 | - ctrl+k
55 | help:
56 | - ctrl+h
57 | quit:
58 | - esc
59 | - ctrl+c
60 | - ctrl+d
61 | jumpstartofinput:
62 | - ctrl+a
63 | jumpendofinput:
64 | - ctrl+e
65 | wordleft:
66 | - ctrl+left
67 | wordright:
68 | - ctrl+right
69 | loglevel: info
70 | fullscreenrendering: false
71 | defaultsearchcolumns:
72 | - command
73 | - hostname
74 | - current_working_directory
75 |
76 |
--------------------------------------------------------------------------------
/client/testdata/TestTimestampFormat-query:
--------------------------------------------------------------------------------
1 | Hostname CWD Timestamp Runtime Exit Code Command
2 | localhost ~/foo/ 2022/Apr/16 01:03 24s 3 table_cmd2
3 | localhost /tmp/ 2022/Apr/16 01:03 4s 2 table_cmd1 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
4 |
--------------------------------------------------------------------------------
/client/testdata/TestTui-AiQuery:
--------------------------------------------------------------------------------
1 | Search Query: > ?myQuery
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname CWD Timestamp Runtime Exit Code Command │
5 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
6 | │ OpenAI N/A N/A N/A 0 result 1 │
7 | │ OpenAI N/A N/A N/A 0 result 2 │
8 | │ OpenAI N/A N/A N/A 0 longer result 3 │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-AiQuery-Disabled:
--------------------------------------------------------------------------------
1 | Search Query: > ?myQuery
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname CWD Timestamp Runtime Exit Code Command │
5 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
6 | │ │
7 | │ │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-ColoredOutput-darwin-23:
--------------------------------------------------------------------------------
1 | Search Query: [90m> [7m[39ml[0m[90ms
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐[39m
4 | [90m│[39m Hostname CWD Timestamp Runtime Exit Code Command [90m│[39m
5 | [90m│────────────────────────────────────────────────────────────────────────────────────────────────────────│[39m
6 | [90m│[93m[104m localhost /tmp/ Oct 17 2022 21:43:21 PDT 3s 2 echo 'aaaaaa bbbb' [90m[49m│[39m
7 | [90m│[39m localhost /tmp/ Oct 17 2022 21:43:16 PDT 3s 2 ls ~/ [90m│[39m
8 | [90m│[39m [90m│[39m
9 | [90m│[39m [90m│[39m
10 | [90m│[39m [90m│[39m
11 | [90m│[39m [90m│[39m
12 | [90m│[39m [90m│[39m
13 | [90m│[39m [90m│[39m
14 | [90m│[39m [90m│[39m
15 | [90m│[39m [90m│[39m
16 | [90m│[39m [90m│[39m
17 | [90m│[39m [90m│[39m
18 | [90m│[39m [90m│[39m
19 | [90m│[39m [90m│[39m
20 | [90m│[39m [90m│[39m
21 | [90m│[39m [90m│[39m
22 | [90m│[39m [90m│[39m
23 | [90m│[39m [90m│[39m
24 | [90m│[39m [90m│[39m
25 | [90m│[39m [90m│[39m
26 | [90m└────────────────────────────────────────────────────────────────────────────────────────────────────────┘[39m
27 | [90mhiSHtory: Search your shell history[39m [90m • ctrl+h[39m [90mhelp [39m
--------------------------------------------------------------------------------
/client/testdata/TestTui-ColoredOutput-linux-actions:
--------------------------------------------------------------------------------
1 | Search Query: [90m> [7m[39ml[0m[90ms
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐[39m
4 | [90m│[39m Hostname CWD Timestamp Runtime Exit Code Command [90m│[39m
5 | [90m│────────────────────────────────────────────────────────────────────────────────────────────────────────│[39m
6 | [90m│[93m[104m localhost /tmp/ Oct 17 2022 21:43:21 PDT 3s 2 echo 'aaaaaa bbbb' [90m[49m│[39m
7 | [90m│[39m localhost /tmp/ Oct 17 2022 21:43:16 PDT 3s 2 ls ~/ [90m│[39m
8 | [90m│[39m [90m│[39m
9 | [90m│[39m [90m│[39m
10 | [90m│[39m [90m│[39m
11 | [90m│[39m [90m│[39m
12 | [90m│[39m [90m│[39m
13 | [90m│[39m [90m│[39m
14 | [90m│[39m [90m│[39m
15 | [90m│[39m [90m│[39m
16 | [90m│[39m [90m│[39m
17 | [90m│[39m [90m│[39m
18 | [90m│[39m [90m│[39m
19 | [90m│[39m [90m│[39m
20 | [90m│[39m [90m│[39m
21 | [90m│[39m [90m│[39m
22 | [90m│[39m [90m│[39m
23 | [90m│[39m [90m│[39m
24 | [90m│[39m [90m│[39m
25 | [90m│[39m [90m│[39m
26 | [90m└────────────────────────────────────────────────────────────────────────────────────────────────────────┘[39m
27 | [90mhiSHtory: Search your shell history[39m [90m • ctrl+h[39m [90mhelp [39m
--------------------------------------------------------------------------------
/client/testdata/TestTui-DefaultColorScheme:
--------------------------------------------------------------------------------
1 | selected-text: #ffff99
2 | selected-background: #3300ff
3 | border-color: #585858
4 |
--------------------------------------------------------------------------------
/client/testdata/TestTui-DefaultFilter-Deleted:
--------------------------------------------------------------------------------
1 | Search Query:
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname CWD Timestamp Runtime Exit Code Command │
5 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
6 | │ localhost /tmp/ Oct 17 2022 21:43:31 PDT 3s 1 exit 1 │
7 | │ localhost /tmp/ Oct 17 2022 21:43:26 PDT 3s 0 exit 0 │
8 | │ localhost /tmp/ Oct 17 2022 21:43:21 PDT 3s 2 echo 'aaaaaa bbbb' │
9 | │ localhost /tmp/ Oct 17 2022 21:43:16 PDT 3s 2 ls ~/ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-DefaultFilter-DeletedWithText:
--------------------------------------------------------------------------------
1 | Search Query: exit
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname CWD Timestamp Runtime Exit Code Command │
5 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
6 | │ localhost /tmp/ Oct 17 2022 21:43:31 PDT 3s 1 exit 1 │
7 | │ localhost /tmp/ Oct 17 2022 21:43:26 PDT 3s 0 exit 0 │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-DefaultFilter-Enabled:
--------------------------------------------------------------------------------
1 | Search Query: [exit_code:0]
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname CWD Timestamp Runtime Exit Code Command │
5 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
6 | │ localhost /tmp/ Oct 17 2022 21:43:26 PDT 3s 0 exit 0 │
7 | │ │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-DefaultFilter-EnabledAdditionalQuery:
--------------------------------------------------------------------------------
1 | Search Query: [exit_code:0] exit
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname CWD Timestamp Runtime Exit Code Command │
5 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
6 | │ localhost /tmp/ Oct 17 2022 21:43:26 PDT 3s 0 exit 0 │
7 | │ │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-DeleteAgainStill:
--------------------------------------------------------------------------------
1 | Search Query: > ls
2 |
3 | ┌───────────────────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname CWD Timestamp Runtime Exit Code Command │
5 | │───────────────────────────────────────────────────────────────────────────────────────────│
6 | │ localhost /tmp/ Oct 17 2022 21:43:16 PDT 3s 2 ls ~/ │
7 | │ │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └───────────────────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-Escaping:
--------------------------------------------------------------------------------
1 | Search Query: > ls
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname CWD Timestamp Runtime Exit Code Command │
5 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
6 | │ localhost /tmp/ Oct 17 2022 21:43:26 PDT 3s 2 "echo 'a\tb\nc'" │
7 | │ localhost /tmp/ Oct 17 2022 21:43:21 PDT 3s 2 echo 'aaaaaa bbbb' │
8 | │ localhost /tmp/ Oct 17 2022 21:43:16 PDT 3s 2 ls ~/ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-Exit-darwin:
--------------------------------------------------------------------------------
1 | runner@ghaction-runner-hostname hishtory % hishtory tquery
2 |
3 | runner@ghaction-runner-hostname hishtory %
--------------------------------------------------------------------------------
/client/testdata/TestTui-Exit-linux:
--------------------------------------------------------------------------------
1 | ghaction-runner-hostname% hishtory tquery
2 |
3 | ghaction-runner-hostname%
--------------------------------------------------------------------------------
/client/testdata/TestTui-ExportWithAdditionalEntries:
--------------------------------------------------------------------------------
1 | ls ~/
2 | echo 'aaaaaa bbbb'
3 | for i in 1
4 | for i in 2
5 | i for in
6 |
--------------------------------------------------------------------------------
/client/testdata/TestTui-ExportWithEvenMoreEntries:
--------------------------------------------------------------------------------
1 | ls ~/
2 | echo 'aaaaaa bbbb'
3 | for i in 1
4 | for i in 2
5 | i for in
6 | foo:bar
7 |
--------------------------------------------------------------------------------
/client/testdata/TestTui-HelpPageClosed:
--------------------------------------------------------------------------------
1 | Search Query: > ls
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname CWD Timestamp Runtime Exit Code Command │
5 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
6 | │ localhost /tmp/ Oct 17 2022 21:43:21 PDT 3s 2 echo 'aaaaaa bbbb' │
7 | │ localhost /tmp/ Oct 17 2022 21:43:16 PDT 3s 2 ls ~/ │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-Initial:
--------------------------------------------------------------------------------
1 | Search Query: > ls
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname CWD Timestamp Runtime Exit Code Command │
5 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
6 | │ localhost /tmp/ Oct 17 2022 21:43:21 PDT 3s 2 echo 'aaaaaa bbbb' │
7 | │ localhost /tmp/ Oct 17 2022 21:43:16 PDT 3s 2 ls ~/ │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-InitialInvalidSearch:
--------------------------------------------------------------------------------
1 | Search Query: > ls
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname CWD Timestamp Runtime Exit Code Command │
5 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
6 | │ localhost /tmp/ Oct 17 2022 21:43:16 PDT 3s 2 ls ~/ │
7 | │ │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-InvalidSearch:
--------------------------------------------------------------------------------
1 | Warning: failed to search: search query contains unknown search atom 'ls' that doesn't match any column names
2 |
3 | Search Query: > ls:
4 |
5 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
6 | │ Hostname CWD Timestamp Runtime Exit Code Command │
7 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
8 | │ localhost /tmp/ Oct 17 2022 21:43:16 PDT 3s 2 ls ~/ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | │ │
27 | │ │
28 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
29 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-InvalidSearchBecomesValid:
--------------------------------------------------------------------------------
1 | Search Query: > ls
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname CWD Timestamp Runtime Exit Code Command │
5 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
6 | │ localhost /tmp/ Oct 17 2022 21:43:16 PDT 3s 2 ls ~/ │
7 | │ │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-JumpCursor:
--------------------------------------------------------------------------------
1 | Search Query: > AAA foo ZZZ
--------------------------------------------------------------------------------
/client/testdata/TestTui-KeyBindings-Configured:
--------------------------------------------------------------------------------
1 | up: up alt+OA ctrl+p
2 | down: ?
3 | page-up: pgup
4 | page-down: pgdown
5 | select-entry: enter
6 | select-entry-and-cd: ctrl+x
7 | left: left
8 | right: right
9 | table-left: shift+left
10 | table-right: shift+right
11 | delete-entry: ctrl+k
12 | help: ctrl+j
13 | quit: esc ctrl+c ctrl+d
14 | jump-start-of-input: ctrl+a
15 | jump-end-of-input: ctrl+e
16 | word-left: ctrl+left
17 | word-right: ctrl+right
18 |
--------------------------------------------------------------------------------
/client/testdata/TestTui-KeyBindings-Default:
--------------------------------------------------------------------------------
1 | up: up alt+OA ctrl+p
2 | down: down alt+OB ctrl+n
3 | page-up: pgup
4 | page-down: pgdown
5 | select-entry: enter
6 | select-entry-and-cd: ctrl+x
7 | left: left
8 | right: right
9 | table-left: shift+left
10 | table-right: shift+right
11 | delete-entry: ctrl+k
12 | help: ctrl+h
13 | quit: esc ctrl+c ctrl+d
14 | jump-start-of-input: ctrl+a
15 | jump-end-of-input: ctrl+e
16 | word-left: ctrl+left
17 | word-right: ctrl+right
18 |
--------------------------------------------------------------------------------
/client/testdata/TestTui-LeftScroll:
--------------------------------------------------------------------------------
1 | Search Query: > ls
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname CWD Timestamp Runtime Exit Code Command │
5 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
6 | │ localhost /tmp/ Oct 17 2022 21:43:16 PDT 3s 2 ls ~/ │
7 | │ │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-LongQuery:
--------------------------------------------------------------------------------
1 | Search Query: > 1234567890qwertyuip1234567890qwertyuip1234567890qwertyuip1234567890qwertyuip12345678
2 | ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
3 | │ Hostname CWD Timestamp Runtime Exit Code Command │
4 | │──────────────────────────────────────────────────────────────────────────────────────────────────│
5 | │ │
6 | │ │
7 | │ │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘
16 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-Offline:
--------------------------------------------------------------------------------
1 | Warning: failed to contact the hishtory backend (are you offline?), so some results may be stale
2 |
3 | Search Query: > ls
4 |
5 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
6 | │ Hostname CWD Timestamp Runtime Exit Code Command │
7 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
8 | │ localhost /tmp/ Oct 17 2022 21:43:21 PDT 3s 2 echo 'aaaaaa bbbb' │
9 | │ localhost /tmp/ Oct 17 2022 21:43:16 PDT 3s 2 ls ~/ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | │ │
27 | │ │
28 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
29 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-OfflineInvalid:
--------------------------------------------------------------------------------
1 | Warning: failed to contact the hishtory backend (are you offline?), so some results may be stale
2 | Warning: failed to search: search query contains unknown search atom 'ls' that doesn't match any column names
3 |
4 | Search Query: > ls:
5 |
6 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
7 | │ Hostname CWD Timestamp Runtime Exit Code Command │
8 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
9 | │ localhost /tmp/ Oct 17 2022 21:43:16 PDT 3s 2 ls ~/ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | │ │
27 | │ │
28 | │ │
29 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
30 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-Search:
--------------------------------------------------------------------------------
1 | Search Query: > ls
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname CWD Timestamp Runtime Exit Code Command │
5 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
6 | │ localhost /tmp/ Oct 17 2022 21:43:16 PDT 3s 2 ls ~/ │
7 | │ │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-SearchBackslash:
--------------------------------------------------------------------------------
1 | Search Query: > for\ i\ in
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname CWD Timestamp Runtime Exit Code Command │
5 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
6 | │ localhost /tmp/ Oct 17 2022 21:43:31 PDT 3s 2 for i in 2 │
7 | │ localhost /tmp/ Oct 17 2022 21:43:26 PDT 3s 2 for i in 1 │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-SearchColonDoubleQuoted:
--------------------------------------------------------------------------------
1 | Search Query: > "foo:bar"
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname CWD Timestamp Runtime Exit Code Command │
5 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
6 | │ localhost /tmp/ Oct 17 2022 21:43:41 PDT 3s 2 foo:bar │
7 | │ │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-SearchColonError:
--------------------------------------------------------------------------------
1 | Warning: failed to search: search query contains unknown search atom 'foo' that doesn't match any column names
2 |
3 | Search Query: > foo:bar
4 |
5 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
6 | │ Hostname CWD Timestamp Runtime Exit Code Command │
7 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
8 | │ localhost /tmp/ Oct 17 2022 21:43:41 PDT 3s 2 foo:bar │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | │ │
27 | │ │
28 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
29 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-SearchColonEscaped:
--------------------------------------------------------------------------------
1 | Search Query: > foo\:bar
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname CWD Timestamp Runtime Exit Code Command │
5 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
6 | │ localhost /tmp/ Oct 17 2022 21:43:41 PDT 3s 2 foo:bar │
7 | │ │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-SearchQuoteDash:
--------------------------------------------------------------------------------
1 | Search Query: > "--bar"
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname CWD Timestamp Runtime Exit Code Command │
5 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
6 | │ localhost /tmp/ Oct 17 2022 21:43:46 PDT 3s 2 foo --bar │
7 | │ │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-SearchQuoted:
--------------------------------------------------------------------------------
1 | Search Query: > "for i in"
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname CWD Timestamp Runtime Exit Code Command │
5 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
6 | │ localhost /tmp/ Oct 17 2022 21:43:31 PDT 3s 2 for i in 2 │
7 | │ localhost /tmp/ Oct 17 2022 21:43:26 PDT 3s 2 for i in 1 │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-SearchUnquoted:
--------------------------------------------------------------------------------
1 | Search Query: > for i in
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname CWD Timestamp Runtime Exit Code Command │
5 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
6 | │ localhost /tmp/ Oct 17 2022 21:43:36 PDT 3s 2 i for in │
7 | │ localhost /tmp/ Oct 17 2022 21:43:31 PDT 3s 2 for i in 2 │
8 | │ localhost /tmp/ Oct 17 2022 21:43:26 PDT 3s 2 for i in 1 │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-SelectAndCd:
--------------------------------------------------------------------------------
1 | cd "/tmp/" && echo 'aaaaaa bbbb'
--------------------------------------------------------------------------------
/client/testdata/TestTui-SmallTerminal:
--------------------------------------------------------------------------------
1 | Search Query: > ls
2 | ┌────────────────────────────────────────────────────────────────────────────────────────────┐
3 | │ Hostname CWD Timestamp Runtime Exit Code Command │
4 | │────────────────────────────────────────────────────────────────────────────────────────────│
5 | │ localhost /tmp/ Oct 17 2022 21:43:21 PDT 3s 2 echo 'aaaaaa bbbb' │
6 | │ localhost /tmp/ Oct 17 2022 21:43:16 PDT 3s 2 ls ~/ │
7 | │ │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | └────────────────────────────────────────────────────────────────────────────────────────────┘
16 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-TiniestTerminal:
--------------------------------------------------------------------------------
1 | Search Query: > ls
2 | ┌────────────────────────────────────────────────────────────────────────────────────────────┐
3 | │ Hostname CWD Timestamp Runtime Exit Code Command │
4 | │────────────────────────────────────────────────────────────────────────────────────────────│
5 | │ localhost /tmp/ Oct 17 2022 21:43:21 PDT 3s 2 echo 'aaaaaa bbbb' │
6 | │ localhost /tmp/ Oct 17 2022 21:43:16 PDT 3s 2 ls ~/ │
7 | │ │
8 | │ │
9 | └────────────────────────────────────────────────────────────────────────────────────────────┘
--------------------------------------------------------------------------------
/client/testdata/TestTui-TinyTerminal:
--------------------------------------------------------------------------------
1 | Search Query: > ls
2 | ┌────────────────────────────────────────────────────────────────────────────────────────────┐
3 | │ Hostname CWD Timestamp Runtime Exit Code Command │
4 | │────────────────────────────────────────────────────────────────────────────────────────────│
5 | │ localhost /tmp/ Oct 17 2022 21:43:21 PDT 3s 2 echo 'aaaaaa bbbb' │
6 | │ localhost /tmp/ Oct 17 2022 21:43:16 PDT 3s 2 ls ~/ │
7 | │ │
8 | │ │
9 | │ │
10 | └────────────────────────────────────────────────────────────────────────────────────────────┘
11 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/TestTui-TinyTerminalHelp:
--------------------------------------------------------------------------------
1 | Search Query: > ls
2 | ┌────────────────────────────────────────────────────────────────────────────────────────────┐
3 | │ Hostname CWD Timestamp Runtime Exit Code Command │
4 | │────────────────────────────────────────────────────────────────────────────────────────────│
5 | │ localhost /tmp/ Oct 17 2022 21:43:21 PDT 3s 2 echo 'aaaaaa bbbb' │
6 | │ localhost /tmp/ Oct 17 2022 21:43:16 PDT 3s 2 ls ~/ │
7 | hiSHtory: Search your shell history
8 | ↑ scroll up
9 | ← move left
10 | enter select an entry
11 | ctrl+x select an entry and cd into that directory
--------------------------------------------------------------------------------
/client/testdata/TestTuiBench-Query:
--------------------------------------------------------------------------------
1 | Search Query: > this is 123
2 | ┌──────────────────────────────────────────────────────────────────────────────────────────────┐
3 | │ Hostname CWD Timestamp Runtime Exit Code Command │
4 | │──────────────────────────────────────────────────────────────────────────────────────────────│
5 | │ localhost /tmp/ Oct 17 2022 21:53:41 P… 3s 2 this is a long co… │
6 | │ │
7 | │ │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | └──────────────────────────────────────────────────────────────────────────────────────────────┘
16 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/testControlR-AdvancedSearch:
--------------------------------------------------------------------------------
1 | Search Query: > cwd:/tmp/ ls
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname CWD Timestamp Runtime Exit Code Command │
5 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
6 | │ localhost /tmp/ Oct 17 2022 21:43:26 PDT 3s 2 ls ~/bar/ │
7 | │ localhost /tmp/ Oct 17 2022 21:43:21 PDT 3s 2 ls ~/foo/ │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/testControlR-ControlC-bash-darwin:
--------------------------------------------------------------------------------
1 | bash-5.2$ source /Users/runner/.bashrc
2 | bash-5.2$ echo
--------------------------------------------------------------------------------
/client/testdata/testControlR-ControlC-bash-linux:
--------------------------------------------------------------------------------
1 | runner@ghaction-runner-hostname:~/work/hishtory/hishtory$ source /home/runner/.bashrc
2 | runner@ghaction-runner-hostname:~/work/hishtory/hishtory$ echo
--------------------------------------------------------------------------------
/client/testdata/testControlR-ControlC-zsh-darwin:
--------------------------------------------------------------------------------
1 | runner@ghaction-runner-hostname hishtory % echo
--------------------------------------------------------------------------------
/client/testdata/testControlR-ControlC-zsh-linux:
--------------------------------------------------------------------------------
1 | ghaction-runner-hostname% echo
--------------------------------------------------------------------------------
/client/testdata/testControlR-DisplayMultiline-bash:
--------------------------------------------------------------------------------
1 | Search Query: > Slah
2 |
3 | ┌─────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname Exit Code Command foo │
5 | │─────────────────────────────────────────────────────────────────────────────│
6 | │ ghaction-runner-hostname 0 ls -Slah / foo │
7 | │ │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └─────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/testControlR-DisplayMultiline-fish:
--------------------------------------------------------------------------------
1 | Search Query: > Slah
2 |
3 | ┌─────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname Exit Code Command foo │
5 | │─────────────────────────────────────────────────────────────────────────────│
6 | │ ghaction-runner-hostname 0 ls -Slah / foo │
7 | │ │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └─────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/testControlR-DisplayMultiline-zsh:
--------------------------------------------------------------------------------
1 | Search Query: > Slah
2 |
3 | ┌───────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname Exit Code Command foo │
5 | │───────────────────────────────────────────────────────────────────────────────│
6 | │ ghaction-runner-hostname 0 "ls \\\n-Slah \\\n/" foo │
7 | │ │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └───────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/testControlR-Final:
--------------------------------------------------------------------------------
1 | Search Query: > -pipefail -exit_code:0
2 |
3 | ┌─────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname Exit Code Command foo │
5 | │─────────────────────────────────────────────────────────────────────────────│
6 | │ localhost 2 echo 'bar' & │
7 | │ localhost 2 echo 'aaaaaa bbbb' │
8 | │ localhost 2 ls ~/bar/ │
9 | │ localhost 2 ls ~/foo/ │
10 | │ server 127 ls ~/ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └─────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/testControlR-Initial:
--------------------------------------------------------------------------------
1 | Search Query: > ls
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname CWD Timestamp Runtime Exit Code Command │
5 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
6 | │ localhost /tmp/ Oct 17 2022 21:43:36 PDT 3s 2 echo 'bar' & │
7 | │ localhost /tmp/ Oct 17 2022 21:43:31 PDT 3s 2 echo 'aaaaaa bbbb' │
8 | │ localhost /tmp/ Oct 17 2022 21:43:26 PDT 3s 2 ls ~/bar/ │
9 | │ localhost /tmp/ Oct 17 2022 21:43:21 PDT 3s 2 ls ~/foo/ │
10 | │ server /etc/ Oct 17 2022 21:43:16 PDT 3s 127 ls ~/ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/testControlR-InitialExport:
--------------------------------------------------------------------------------
1 | ls ~/
2 | ls ~/foo/
3 | ls ~/bar/
4 | echo 'aaaaaa bbbb'
5 | echo 'bar' &
6 |
--------------------------------------------------------------------------------
/client/testdata/testControlR-InitialSearch:
--------------------------------------------------------------------------------
1 | Search Query: > ls
2 |
3 | ┌─────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname Exit Code Command foo │
5 | │─────────────────────────────────────────────────────────────────────────────│
6 | │ ghaction-runner-hostname 0 ls / foo │
7 | │ localhost 2 ls ~/bar/ │
8 | │ localhost 2 ls ~/foo/ │
9 | │ server 127 ls ~/ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └─────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/testControlR-InitialSearchExpanded:
--------------------------------------------------------------------------------
1 | Search Query: > echo
2 |
3 | ┌─────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname Exit Code Command foo │
5 | │─────────────────────────────────────────────────────────────────────────────│
6 | │ localhost 2 echo 'bar' & │
7 | │ localhost 2 echo 'aaaaaa bbbb' │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └─────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/testControlR-InitialSearchNoResults:
--------------------------------------------------------------------------------
1 | Search Query: > asdf
2 |
3 | ┌─────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname Exit Code Command foo │
5 | │─────────────────────────────────────────────────────────────────────────────│
6 | │ │
7 | │ │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └─────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/testControlR-InitialSearchNoResultsThenFoundResults:
--------------------------------------------------------------------------------
1 | Search Query: > echo
2 |
3 | ┌─────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname Exit Code Command foo │
5 | │─────────────────────────────────────────────────────────────────────────────│
6 | │ localhost 2 echo 'bar' & │
7 | │ localhost 2 echo 'aaaaaa bbbb' │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └─────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/testControlR-Search:
--------------------------------------------------------------------------------
1 | Search Query: > echo
2 |
3 | ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname CWD Timestamp Runtime Exit Code Command │
5 | │────────────────────────────────────────────────────────────────────────────────────────────────────────│
6 | │ localhost /tmp/ Oct 17 2022 21:43:36 PDT 3s 2 echo 'bar' & │
7 | │ localhost /tmp/ Oct 17 2022 21:43:31 PDT 3s 2 echo 'aaaaaa bbbb' │
8 | │ │
9 | │ │
10 | │ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/testControlR-SelectMultiline-bash-darwin:
--------------------------------------------------------------------------------
1 | bash-5.2$ source /Users/runner/.bashrc
2 | bash-5.2$ ls -Slah /
--------------------------------------------------------------------------------
/client/testdata/testControlR-SelectMultiline-bash-linux:
--------------------------------------------------------------------------------
1 | runner@ghaction-runner-hostname:~/work/hishtory/hishtory$ source /home/runner/.bashrc
2 | runner@ghaction-runner-hostname:~/work/hishtory/hishtory$ ls -Slah /
--------------------------------------------------------------------------------
/client/testdata/testControlR-SelectMultiline-zsh-darwin:
--------------------------------------------------------------------------------
1 | runner@ghaction-runner-hostname hishtory % ls \
2 | -Slah \
3 | /
--------------------------------------------------------------------------------
/client/testdata/testControlR-SelectMultiline-zsh-linux:
--------------------------------------------------------------------------------
1 | ghaction-runner-hostname% ls \
2 | -Slah \
3 | /
--------------------------------------------------------------------------------
/client/testdata/testControlR-bash-Disabled-darwin:
--------------------------------------------------------------------------------
1 | bash-5.2$ source /Users/runner/.bashrc
2 | (reverse-i-search)`':
--------------------------------------------------------------------------------
/client/testdata/testControlR-bash-Disabled-linux:
--------------------------------------------------------------------------------
1 | runner@ghaction-runner-hostname:~/work/hishtory/hishtory$ source /home/runner/.bashrc
2 | (reverse-i-search)`':
--------------------------------------------------------------------------------
/client/testdata/testControlR-customColumn:
--------------------------------------------------------------------------------
1 | Search Query: > -pipefail
2 |
3 | ┌─────────────────────────────────────────────────────────────────────────────┐
4 | │ Hostname Exit Code Command foo │
5 | │─────────────────────────────────────────────────────────────────────────────│
6 | │ ghaction-runner-hostname 0 ls / foo │
7 | │ localhost 2 echo 'bar' & │
8 | │ localhost 2 echo 'aaaaaa bbbb' │
9 | │ localhost 2 ls ~/bar/ │
10 | │ localhost 2 ls ~/foo/ │
11 | │ server 127 ls ~/ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └─────────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/testControlR-displayedColumns:
--------------------------------------------------------------------------------
1 | Search Query: > ls
2 |
3 | ┌────────────────────────────────────────────────────┐
4 | │ Hostname Exit Code Command │
5 | │────────────────────────────────────────────────────│
6 | │ localhost 2 echo 'bar' & │
7 | │ localhost 2 echo 'aaaaaa bbbb' │
8 | │ localhost 2 ls ~/bar/ │
9 | │ localhost 2 ls ~/foo/ │
10 | │ server 127 ls ~/ │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/testControlR-zsh-Disabled-darwin:
--------------------------------------------------------------------------------
1 | runner@ghaction-runner-hostname hishtory %
2 | bck-i-search: _
--------------------------------------------------------------------------------
/client/testdata/testControlR-zsh-Disabled-linux:
--------------------------------------------------------------------------------
1 | ghaction-runner-hostname%
2 | bck-i-search: _
--------------------------------------------------------------------------------
/client/testdata/testCustomColumns-initHistory:
--------------------------------------------------------------------------------
1 | export FOOBAR='hello'
2 | echo $FOOBAR world
3 | cd /
4 | echo baz
5 |
--------------------------------------------------------------------------------
/client/testdata/testCustomColumns-query-isAction=false:
--------------------------------------------------------------------------------
1 | Exit Code git_remote Command
2 | 0 git@github.com:ddworken/hishtory.git hishtory config-set displayed-columns 'Exit Code' git_remote Command
3 | 0 echo bar
4 | 0 cd /
5 | 0 git@github.com:ddworken/hishtory.git echo foo
6 | 0 git@github.com:ddworken/hishtory.git hishtory config-add custom-columns git_remote '(git remote -v 2>/dev/null | grep origin 1>/dev/null ) && git remote get-url origin || true'
7 | 0 echo baz
8 | 0 cd /
9 | 0 echo $FOOBAR world
10 | 0 export FOOBAR='hello'
11 |
--------------------------------------------------------------------------------
/client/testdata/testCustomColumns-query-isAction=true:
--------------------------------------------------------------------------------
1 | Exit Code git_remote Command
2 | 0 https://github.com/ddworken/hishtory hishtory config-set displayed-columns 'Exit Code' git_remote Command
3 | 0 echo bar
4 | 0 cd /
5 | 0 https://github.com/ddworken/hishtory echo foo
6 | 0 https://github.com/ddworken/hishtory hishtory config-add custom-columns git_remote '(git remote -v 2>/dev/null | grep origin 1>/dev/null ) && git remote get-url origin || true'
7 | 0 echo baz
8 | 0 cd /
9 | 0 echo $FOOBAR world
10 | 0 export FOOBAR='hello'
11 |
--------------------------------------------------------------------------------
/client/testdata/testDisplayTable-customColumns:
--------------------------------------------------------------------------------
1 | Hostname Command
2 | localhost table_cmd2
3 | localhost table_cmd1
4 |
--------------------------------------------------------------------------------
/client/testdata/testDisplayTable-customColumns-2:
--------------------------------------------------------------------------------
1 | Hostname Exit Code Command
2 | localhost 3 table_cmd2
3 | localhost 2 table_cmd1
4 |
--------------------------------------------------------------------------------
/client/testdata/testDisplayTable-customColumns-3:
--------------------------------------------------------------------------------
1 | Hostname Exit Code Command CWD
2 | localhost 3 table_cmd2 ~/foo/
3 | localhost 2 table_cmd1 /tmp/
4 |
--------------------------------------------------------------------------------
/client/testdata/testDisplayTable-customColumns-multiLineCommand:
--------------------------------------------------------------------------------
1 | Hostname Exit Code Command CWD
2 | localhost 2 while : /tmp/
3 | do
4 | ls /table/
5 | done
6 | localhost 3 table_cmd2 ~/foo/
7 | localhost 2 table_cmd1 /tmp/
8 |
--------------------------------------------------------------------------------
/client/testdata/testDisplayTable-customColumns-trulyCustom:
--------------------------------------------------------------------------------
1 | Hostname Exit Code Command CWD foo
2 | ghaction-runner-hostname 0 echo table-2 / aaaaaaaaaaaaa
3 | ghaction-runner-hostname 0 echo table-1 / aaaaaaaaaaaaa
4 | localhost 2 while : /tmp/
5 | do
6 | ls /table/
7 | done
8 | localhost 3 table_cmd2 ~/foo/
9 | localhost 2 table_cmd1 /tmp/
10 |
--------------------------------------------------------------------------------
/client/testdata/testDisplayTable-defaultColumns:
--------------------------------------------------------------------------------
1 | Hostname CWD Timestamp Runtime Exit Code Command
2 | localhost ~/foo/ Apr 16 2022 01:03:16 PDT 24s 3 table_cmd2
3 | localhost /tmp/ Apr 16 2022 01:03:06 PDT 4s 2 table_cmd1
4 |
--------------------------------------------------------------------------------
/client/testdata/testIntegrationWithNewDevice-bash:
--------------------------------------------------------------------------------
1 | hishtory status
2 | hishtory query
3 | ls /a
4 | ls /bar
5 | ls /foo
6 | echo foo
7 | echo bar
8 | hishtory disable
9 | hishtory enable
10 | echo thisisrecorded
11 | hishtory query
12 | hishtory query foo
13 | echo hello | grep complex | sed s/h/i/g; echo baz && echo "fo 'o" # mycommand
14 | hishtory query complex
15 | hishtory query
16 | echo mynewcommand
17 | hishtory query
18 | hishtory query
19 | echo mynewercommand
20 | hishtory query
21 | othercomputer
22 | hishtory query
23 | hishtory reupload
24 |
--------------------------------------------------------------------------------
/client/testdata/testIntegrationWithNewDevice-tablebash:
--------------------------------------------------------------------------------
1 | Hostname Exit Code Command
2 | ghaction-runner-hostname 0 hishtory config-set displayed-columns Hostname 'Exit Code' Command
3 | ghaction-runner-hostname 0 hishtory reupload
4 | ghaction-runner-hostname 0 hishtory query
5 | localhost 2 othercomputer
6 | ghaction-runner-hostname 0 hishtory query
7 | ghaction-runner-hostname 0 echo mynewercommand
8 | ghaction-runner-hostname 0 hishtory query
9 | ghaction-runner-hostname 0 hishtory query
10 | ghaction-runner-hostname 0 echo mynewcommand
11 | ghaction-runner-hostname 0 hishtory query
12 | ghaction-runner-hostname 0 hishtory query complex
13 | ghaction-runner-hostname 0 echo hello | grep complex | sed s/h/i/g; echo baz && echo "fo 'o" # mycommand
14 | ghaction-runner-hostname 0 hishtory query foo
15 | ghaction-runner-hostname 0 hishtory query
16 | ghaction-runner-hostname 0 echo thisisrecorded
17 | ghaction-runner-hostname 0 hishtory enable
18 | ghaction-runner-hostname 0 hishtory disable
19 | ghaction-runner-hostname 0 echo bar
20 | ghaction-runner-hostname 0 echo foo
21 | ghaction-runner-hostname 0 hishtory query
22 | ghaction-runner-hostname 0 hishtory status
23 |
--------------------------------------------------------------------------------
/client/testdata/testIntegrationWithNewDevice-tablezsh:
--------------------------------------------------------------------------------
1 | Hostname Exit Code Command
2 | ghaction-runner-hostname 0 hishtory config-set displayed-columns Hostname 'Exit Code' Command
3 | ghaction-runner-hostname 0 hishtory reupload
4 | ghaction-runner-hostname 0 hishtory query
5 | localhost 2 othercomputer
6 | ghaction-runner-hostname 0 hishtory query
7 | ghaction-runner-hostname 0 echo mynewercommand
8 | ghaction-runner-hostname 0 hishtory query
9 | ghaction-runner-hostname 0 hishtory query
10 | ghaction-runner-hostname 0 echo mynewcommand
11 | ghaction-runner-hostname 0 hishtory query
12 | ghaction-runner-hostname 0 hishtory query complex
13 | ghaction-runner-hostname 0 echo hello | grep complex | sed s/h/i/g; echo baz && echo "fo 'o" # mycommand
14 | ghaction-runner-hostname 0 hishtory query foo
15 | ghaction-runner-hostname 0 hishtory query
16 | ghaction-runner-hostname 0 echo thisisrecorded
17 | ghaction-runner-hostname 0 hishtory enable
18 | ghaction-runner-hostname 0 hishtory disable
19 | ghaction-runner-hostname 0 echo bar
20 | ghaction-runner-hostname 0 echo foo
21 | ghaction-runner-hostname 0 hishtory query
22 | ghaction-runner-hostname 0 hishtory status
23 |
--------------------------------------------------------------------------------
/client/testdata/testIntegrationWithNewDevice-zsh:
--------------------------------------------------------------------------------
1 | hishtory status
2 | hishtory query
3 | ls /a
4 | ls /bar
5 | ls /foo
6 | echo foo
7 | echo bar
8 | hishtory disable
9 | hishtory enable
10 | echo thisisrecorded
11 | hishtory query
12 | hishtory query foo
13 | echo hello | grep complex | sed s/h/i/g; echo baz && echo "fo 'o" # mycommand
14 | hishtory query complex
15 | hishtory query
16 | echo mynewcommand
17 | hishtory query
18 | hishtory query
19 | echo mynewercommand
20 | hishtory query
21 | othercomputer
22 | hishtory query
23 | hishtory reupload
24 |
--------------------------------------------------------------------------------
/client/testdata/testPresaving-query:
--------------------------------------------------------------------------------
1 | CWD Runtime Command
2 | / N/A sleep 13371337
3 |
--------------------------------------------------------------------------------
/client/testdata/testPresavingOffline-query-missing:
--------------------------------------------------------------------------------
1 | CWD Runtime Command
2 |
--------------------------------------------------------------------------------
/client/testdata/testPresavingOffline-query-present:
--------------------------------------------------------------------------------
1 | CWD Runtime Command
2 | / N/A sleep 13371336
3 |
--------------------------------------------------------------------------------
/client/testdata/testRemoveDuplicateRows-enabled-export:
--------------------------------------------------------------------------------
1 | echo foo
2 | echo foo
3 | echo baz
4 | echo baz
5 | echo foo
6 | hishtory config-set displayed-columns 'Exit Code' Command
7 | hishtory tquery
8 | hishtory config-set filter-duplicate-commands true
9 |
--------------------------------------------------------------------------------
/client/testdata/testRemoveDuplicateRows-enabled-query:
--------------------------------------------------------------------------------
1 | Exit Code Command
2 | 0 hishtory config-set filter-duplicate-commands true
3 | 0 hishtory tquery
4 | 0 hishtory config-set displayed-columns 'Exit Code' Command
5 | 0 echo foo
6 | 0 echo baz
7 |
--------------------------------------------------------------------------------
/client/testdata/testRemoveDuplicateRows-enabled-tquery:
--------------------------------------------------------------------------------
1 | Search Query: > -pipefail
2 |
3 | ┌───────────────────────────────────────────────────────────────────────────┐
4 | │ Exit Code Command │
5 | │───────────────────────────────────────────────────────────────────────────│
6 | │ 0 hishtory tquery │
7 | │ 0 hishtory config-set filter-duplicate-commands true │
8 | │ 0 hishtory config-set displayed-columns 'Exit Code' Command │
9 | │ 0 echo foo │
10 | │ 0 echo baz │
11 | │ │
12 | │ │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └───────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/testRemoveDuplicateRows-export:
--------------------------------------------------------------------------------
1 | echo foo
2 | echo foo
3 | echo baz
4 | echo baz
5 | echo foo
6 |
--------------------------------------------------------------------------------
/client/testdata/testRemoveDuplicateRows-query:
--------------------------------------------------------------------------------
1 | Exit Code Command
2 | 0 hishtory config-set displayed-columns 'Exit Code' Command
3 | 0 echo foo
4 | 0 echo baz
5 | 0 echo baz
6 | 0 echo foo
7 | 0 echo foo
8 |
--------------------------------------------------------------------------------
/client/testdata/testRemoveDuplicateRows-tquery:
--------------------------------------------------------------------------------
1 | Search Query: > -pipefail
2 |
3 | ┌───────────────────────────────────────────────────────────────────────────┐
4 | │ Exit Code Command │
5 | │───────────────────────────────────────────────────────────────────────────│
6 | │ 0 hishtory tquery │
7 | │ 0 hishtory config-set displayed-columns 'Exit Code' Command │
8 | │ 0 echo foo │
9 | │ 0 echo baz │
10 | │ 0 echo baz │
11 | │ 0 echo foo │
12 | │ 0 echo foo │
13 | │ │
14 | │ │
15 | │ │
16 | │ │
17 | │ │
18 | │ │
19 | │ │
20 | │ │
21 | │ │
22 | │ │
23 | │ │
24 | │ │
25 | │ │
26 | └───────────────────────────────────────────────────────────────────────────┘
27 | hiSHtory: Search your shell history • ctrl+h help
--------------------------------------------------------------------------------
/client/testdata/testTabCompletion-suggestions-fish:
--------------------------------------------------------------------------------
1 | config-add (Add a config option) config-delete (Delete a config option) config-get (Get the value of a config option) config-set (Set the value of a config option)
--------------------------------------------------------------------------------
/client/testdata/testTabCompletion-suggestions-zsh:
--------------------------------------------------------------------------------
1 | config-add -- Add a config option
2 | config-delete -- Delete a config option
3 | config-get -- Get the value of a config option
4 | config-set -- Set the value of a config option
--------------------------------------------------------------------------------
/client/testdata/testUninstall-post-uninstall:
--------------------------------------------------------------------------------
1 | foo
2 | bar
3 |
--------------------------------------------------------------------------------
/client/testdata/testUninstall-post-uninstall-bash-darwin:
--------------------------------------------------------------------------------
1 | bash-5.2$ source /Users/runner/.bashrc
2 | bash-5.2$ echo foo
3 | foo
4 | bash-5.2$ hishtory
5 | bash: hishtory: command not found
6 | bash-5.2$ echo bar
7 | bar
8 | bash-5.2$
--------------------------------------------------------------------------------
/client/testdata/testUninstall-post-uninstall-bash-linux:
--------------------------------------------------------------------------------
1 | runner@ghaction-runner-hostname:~/work/hishtory/hishtory$ source /home/runner/.bashrc
2 | runner@ghaction-runner-hostname:~/work/hishtory/hishtory$ echo foo
3 | foo
4 | runner@ghaction-runner-hostname:~/work/hishtory/hishtory$ hishtory
5 | hishtory: command not found
6 | runner@ghaction-runner-hostname:~/work/hishtory/hishtory$ echo bar
7 | bar
8 | runner@ghaction-runner-hostname:~/work/hishtory/hishtory$
--------------------------------------------------------------------------------
/client/testdata/testUninstall-post-uninstall-zsh-darwin:
--------------------------------------------------------------------------------
1 | runner@ghaction-runner-hostname hishtory % echo foo
2 | foo
3 | runner@ghaction-runner-hostname hishtory % hishtory
4 | zsh: command not found: hishtory
5 | runner@ghaction-runner-hostname hishtory % echo bar
6 | bar
7 | runner@ghaction-runner-hostname hishtory %
--------------------------------------------------------------------------------
/client/testdata/testUninstall-post-uninstall-zsh-linux:
--------------------------------------------------------------------------------
1 | ghaction-runner-hostname% echo foo
2 | foo
3 | ghaction-runner-hostname% hishtory
4 | zsh: command not found: hishtory
5 | ghaction-runner-hostname% echo bar
6 | bar
7 | ghaction-runner-hostname%
--------------------------------------------------------------------------------
/client/testdata/testUninstall-recorded:
--------------------------------------------------------------------------------
1 | echo foo
2 | echo baz
3 |
--------------------------------------------------------------------------------
/client/testdata/testUninstall-uninstall-bash:
--------------------------------------------------------------------------------
1 | Are you sure you want to uninstall hiSHtory and delete all locally saved history data [y/N]Do you have any feedback on why you're uninstallying hiSHtory? Type any feedback and then hit enter.
2 | Feedback: Successfully uninstalled hishtory, please restart your terminal...
3 | bash: /home/runner/.hishtory/hishtory: No such file or directory
4 | bash: /home/runner/.hishtory/hishtory: No such file or directory
5 |
--------------------------------------------------------------------------------
/client/testdata/testUninstall-uninstall-zsh:
--------------------------------------------------------------------------------
1 | Are you sure you want to uninstall hiSHtory and delete all locally saved history data [y/N]Do you have any feedback on why you're uninstallying hiSHtory? Type any feedback and then hit enter.
2 | Feedback: Successfully uninstalled hishtory, please restart your terminal...
3 | _hishtory_precmd:8: command not found: hishtory
4 | _hishtory_precmd:9: command not found: hishtory
5 |
--------------------------------------------------------------------------------
/client/testdata/unittestTable-truncatedTable:
--------------------------------------------------------------------------------
1 | Column1 Column2
2 | a1 a2345
3 | b1 b23
4 | c1 c1234567890abcdefgh…
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/client/testdata/unittestTable-truncatedTable-right1:
--------------------------------------------------------------------------------
1 | Column1 Column2
2 | a1 …2345
3 | b1 …23
4 | c1 …1234567890abcdefgh…
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/client/testdata/unittestTable-truncatedTable-right2:
--------------------------------------------------------------------------------
1 | Column1 Column2
2 | a1 …345
3 | b1 …3
4 | c1 …234567890abcdefghi…
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/client/testdata/unittestTable-truncatedTable-right3:
--------------------------------------------------------------------------------
1 | Column1 Column2
2 | a1 …45
3 | b1 …
4 | c1 …34567890abcdefghij…
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/client/tui/tui_test.go:
--------------------------------------------------------------------------------
1 | package tui
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 | )
8 |
9 | func TestCalculateWordBoundaries(t *testing.T) {
10 | require.Equal(t, []int{0, 3}, calculateWordBoundaries("foo"))
11 | require.Equal(t, []int{0, 3, 7}, calculateWordBoundaries("foo bar"))
12 | require.Equal(t, []int{0, 3, 7}, calculateWordBoundaries("foo-bar"))
13 | require.Equal(t, []int{0, 3, 7, 11}, calculateWordBoundaries("foo-bar baz"))
14 | require.Equal(t, []int{0, 3, 10, 16}, calculateWordBoundaries("foo-- -bar - baz"))
15 | require.Equal(t, []int{0, 3}, calculateWordBoundaries("foo "))
16 | }
17 |
18 | func TestSanitizeEscapeCodes(t *testing.T) {
19 | require.Equal(t, "foo", sanitizeEscapeCodes("foo"))
20 | require.Equal(t, "foo\x1b[31mbar", sanitizeEscapeCodes("foo\x1b[31mbar"))
21 | require.Equal(t, "", sanitizeEscapeCodes("11;rgb:1c1c/1c1c/1c1c"))
22 | require.Equal(t, "foo bar", sanitizeEscapeCodes("foo 11;rgb:1c1c/1c1c/1c1c bar"))
23 | }
24 |
--------------------------------------------------------------------------------
/client/webui/templates/webui.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
hiSHtory
5 |
Your shell history in context, synced, and queryable
6 |
7 |
8 |
9 |
10 |
34 |
35 |
36 |
37 | {{ block "resultsTable.html" . }}
38 |
39 |
40 |
41 |
42 | {{ range .ColumnNames }}
43 | {{ . }} |
44 | {{ end }}
45 |
46 |
47 |
48 | {{ range .SearchResults }}
49 |
50 | {{ range . }}
51 | {{ . }} |
52 | {{ end }}
53 |
54 | {{ end }}
55 |
56 |
57 |
58 | {{ end }}
59 |
60 |
61 |
67 |
72 |
77 |
--------------------------------------------------------------------------------
/demo.vhs:
--------------------------------------------------------------------------------
1 | # Demo file uses https://github.com/charmbracelet/vhs
2 |
3 | Output backend/web/landing/www/img/demo.gif
4 | Set FontSize 22
5 | Set Width 2300
6 | Set Height 1050
7 |
8 | # Set up
9 | Hide
10 | Type "zsh"
11 | Enter
12 | Type "setopt interactivecomments"
13 | Enter
14 | Type "clear"
15 | Enter
16 | Set TypingSpeed 0.1
17 | Show
18 |
19 | Type "find . -iname '*.go' | xargs -I {} -- gofmt -w {}"
20 | Enter
21 | Sleep 4000ms
22 |
23 | Type "ssh server"
24 | Enter
25 | Sleep 400ms
26 | Type "# Then press control + r to search your history"
27 | Enter
28 | Sleep 3800ms
29 |
30 | Ctrl+R
31 | Sleep 6000ms
32 | Type "g"
33 | Sleep 400ms
34 | Type "of
35 | Sleep 400ms
36 | Type "mt"
37 | Sleep 1000ms
38 | Type " cwd:~/code/hishtory/"
39 | Sleep 7000ms
40 | Enter
41 | Sleep 6000ms
42 |
--------------------------------------------------------------------------------
/docs/offline-binary.md:
--------------------------------------------------------------------------------
1 | # Offline Binary
2 |
3 | hiSHtory supports disabling syncing at install-time via `curl https://hishtory.dev/install.py | python3 - --offline` or at config-time via `hishtory syncing disable`. This will disable persisting your (encrypted) history on the backend API server. For most users, this is the recommended option for running hiSHtory in an offline environment since it still supports opt-in updates via `hishtory update`.
4 |
5 | But, if you need stronger guarantees that hiSHtory will not make any network requests, this can also be done by compiling your own copy of hiSHtory with the `offline` tag. This will statically link in [`net_disabled.go`](https://github.com/ddworken/hishtory/blob/master/client/lib/net_disabled.go) which will guarantee that the binary cannot make any HTTP requests. To use this:
6 |
7 | ```
8 | git clone https://github.com/ddworken/hishtory
9 | cd hishtory
10 | go build -tags offline
11 | ./hishtory install
12 | ```
13 |
14 | This binary will be entirely offline and is guaranteed to never make any requests to `api.hishtory.dev`.
15 |
--------------------------------------------------------------------------------
/hishtory.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/ddworken/hishtory/client/cmd"
5 | "github.com/ddworken/hishtory/client/data"
6 | "github.com/ddworken/hishtory/client/lib"
7 | )
8 |
9 | func main() {
10 | lib.CheckFatalError(data.ValidateHishtoryPath())
11 | cmd.Execute()
12 | }
13 |
14 | // TODO(feature): Add a session_id column that corresponds to the shell session the command was run in
15 | // TODO(feature): Add a shell column that contains the shell name
16 |
--------------------------------------------------------------------------------
/scripts/actions-sign.py:
--------------------------------------------------------------------------------
1 | import os
2 | import time
3 | import subprocess
4 |
5 | def main():
6 | assertPresentAndNotAscii("hishtory-darwin-arm64")
7 | assertPresentAndNotAscii("hishtory-darwin-amd64")
8 |
9 | print("before sha1sum:")
10 | os.system("sha1sum hishtory-* 2>&1")
11 | print("before sha256sum:")
12 | os.system("sha256sum hishtory-* 2>&1")
13 |
14 | print("file:")
15 | os.system("file hishtory-* 2>&1")
16 |
17 | print("signing...")
18 | os.system("""
19 | set -emo pipefail
20 | cp hishtory-darwin-arm64 hishtory-darwin-arm64-unsigned
21 | cp hishtory-darwin-amd64 hishtory-darwin-amd64-unsigned
22 | echo $MACOS_CERTIFICATE | base64 -d > certificate.p12
23 | security create-keychain -p $MACOS_CERTIFICATE_PWD build.keychain
24 | security default-keychain -s build.keychain
25 | security unlock-keychain -p $MACOS_CERTIFICATE_PWD build.keychain
26 | security import certificate.p12 -k build.keychain -P $MACOS_CERTIFICATE_PWD -T /usr/bin/codesign
27 | security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $MACOS_CERTIFICATE_PWD build.keychain
28 | /usr/bin/codesign --force -s 6D4E1575A0D40C370E294916A8390797106C8A6E hishtory-darwin-arm64 -v
29 | /usr/bin/codesign --force -s 6D4E1575A0D40C370E294916A8390797106C8A6E hishtory-darwin-amd64 -v
30 | """)
31 |
32 | print("after sha1sum:")
33 | os.system("sha1sum hishtory-* 2>&1")
34 | print("after sha256sum:")
35 | os.system("sha256sum hishtory-* 2>&1")
36 |
37 |
38 | def assertPresentAndNotAscii(fn):
39 | if not os.path.exists(fn):
40 | raise Exception(f"{fn=} does not exist, did it fail to download?")
41 | out = subprocess.check_output(["file", fn]).decode('utf-8')
42 | if "ASCII text" in out:
43 | raise Exception(f"{fn=} is of type {out}")
44 |
45 | if __name__ == '__main__':
46 | main()
--------------------------------------------------------------------------------
/scripts/client-ldflags:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | GIT_HASH=$(git rev-parse HEAD)
4 | echo "-X github.com/ddworken/hishtory/client/lib.GitCommit=$GIT_HASH -X github.com/ddworken/hishtory/client/lib.Version=`cat VERSION` -w -extldflags \"-static\""
5 |
--------------------------------------------------------------------------------
/shared/ai/ai_test.go:
--------------------------------------------------------------------------------
1 | package ai
2 |
3 | import (
4 | "os"
5 | "strings"
6 | "testing"
7 |
8 | "github.com/ddworken/hishtory/shared/testutils"
9 |
10 | "github.com/stretchr/testify/require"
11 | )
12 |
13 | // A basic sanity test that our integration with the OpenAI API is correct and is returning reasonable results (at least for a very basic query)
14 | func TestLiveOpenAiApi(t *testing.T) {
15 | if os.Getenv("OPENAI_API_KEY") == "" {
16 | if testutils.IsGithubAction() && testutils.GetCurrentGitBranch(t) == testutils.DefaultGitBranchName {
17 | t.Fatal("OPENAI_API_KEY is not set, cannot run TestLiveOpenAiApi")
18 | } else {
19 | t.Skip("Skipping test since OPENAI_API_KEY is not set")
20 | }
21 | }
22 | results, _, err := GetAiSuggestionsViaOpenAiApi("https://api.openai.com/v1/chat/completions", "list files in the current directory", "bash", "Linux", "", 3)
23 | require.NoError(t, err)
24 | resultsContainsLs := false
25 | for _, result := range results {
26 | if strings.Contains(result, "ls") {
27 | resultsContainsLs = true
28 | }
29 | }
30 | require.Truef(t, resultsContainsLs, "expected results=%#v to contain ls", results)
31 | }
32 |
--------------------------------------------------------------------------------
/shared/time.go:
--------------------------------------------------------------------------------
1 | package shared
2 |
3 | const DateOnly = "2006-01-02"
4 |
--------------------------------------------------------------------------------
/shared/utils.go:
--------------------------------------------------------------------------------
1 | package shared
2 |
3 | import "sync"
4 |
5 | func ForEach[T any](arr []T, numThreads int, fn func(T) error) error {
6 | wg := &sync.WaitGroup{}
7 | wg.Add(len(arr))
8 |
9 | limiter := make(chan bool, numThreads)
10 |
11 | var errors []error
12 | for _, item := range arr {
13 | limiter <- true
14 | go func(x T) {
15 | defer wg.Done()
16 | err := fn(x)
17 | if err != nil {
18 | errors = append(errors, err)
19 | }
20 | <-limiter
21 | }(item)
22 | if len(errors) > 0 {
23 | return errors[0]
24 | }
25 | }
26 |
27 | wg.Wait()
28 | if len(errors) > 0 {
29 | return errors[0]
30 | }
31 | return nil
32 | }
33 |
--------------------------------------------------------------------------------
/shared/version.go:
--------------------------------------------------------------------------------
1 | package shared
2 |
3 | import (
4 | "fmt"
5 | "regexp"
6 | "strconv"
7 | )
8 |
9 | type ParsedVersion struct {
10 | MajorVersion int
11 | MinorVersion int
12 | }
13 |
14 | func (pv ParsedVersion) GreaterThan(other ParsedVersion) bool {
15 | if pv.MajorVersion == other.MajorVersion && pv.MinorVersion == other.MinorVersion {
16 | return false
17 | }
18 | return !pv.LessThan(other)
19 | }
20 |
21 | func (pv ParsedVersion) LessThan(other ParsedVersion) bool {
22 | if pv.MajorVersion != other.MajorVersion {
23 | return pv.MajorVersion < other.MajorVersion
24 | }
25 | return pv.MinorVersion < other.MinorVersion
26 | }
27 |
28 | func (pv ParsedVersion) Decrement() ParsedVersion {
29 | if pv.MinorVersion > 1 {
30 | return ParsedVersion{pv.MajorVersion, pv.MinorVersion - 1}
31 | }
32 | panic("cannot decrement() when MinorVersion == 0")
33 | }
34 |
35 | func (pv ParsedVersion) String() string {
36 | return fmt.Sprintf("v%d.%d", pv.MajorVersion, pv.MinorVersion)
37 | }
38 |
39 | func ParseVersionString(versionString string) (ParsedVersion, error) {
40 | re := regexp.MustCompile(`v(\d+)[.](\d+)`)
41 | matches := re.FindAllStringSubmatch(versionString, -1)
42 | if len(matches) != 1 {
43 | return ParsedVersion{}, fmt.Errorf("failed to parse version=%#v (matches=%#v)", versionString, matches)
44 | }
45 | if len(matches[0]) != 3 {
46 | return ParsedVersion{}, fmt.Errorf("failed to parse version=%#v (matches[0]=%#v)", versionString, matches[0])
47 | }
48 | MajorVersion, err := strconv.Atoi(matches[0][1])
49 | if err != nil {
50 | return ParsedVersion{}, fmt.Errorf("failed to parse major version %#v", matches[0][1])
51 | }
52 | MinorVersion, err := strconv.Atoi(matches[0][2])
53 | if err != nil {
54 | return ParsedVersion{}, fmt.Errorf("failed to parse minor version %#v", matches[0][2])
55 | }
56 | return ParsedVersion{MajorVersion, MinorVersion}, nil
57 | }
58 |
--------------------------------------------------------------------------------
/shared/version_test.go:
--------------------------------------------------------------------------------
1 | package shared
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 | )
8 |
9 | func TestParseVersionString(t *testing.T) {
10 | p, err := ParseVersionString("v0.200")
11 | require.NoError(t, err)
12 | require.Equal(t, ParsedVersion{MajorVersion: 0, MinorVersion: 200}, p)
13 | p, err = ParseVersionString("v1.200")
14 | require.NoError(t, err)
15 | require.Equal(t, ParsedVersion{MajorVersion: 1, MinorVersion: 200}, p)
16 | p, err = ParseVersionString("v1.0")
17 | require.NoError(t, err)
18 | require.Equal(t, ParsedVersion{MajorVersion: 1, MinorVersion: 0}, p)
19 | p, err = ParseVersionString("v0.216")
20 | require.NoError(t, err)
21 | require.Equal(t, ParsedVersion{MajorVersion: 0, MinorVersion: 216}, p)
22 | p, err = ParseVersionString("v123.456")
23 | require.NoError(t, err)
24 | require.Equal(t, ParsedVersion{MajorVersion: 123, MinorVersion: 456}, p)
25 | }
26 |
27 | func TestVersionLessThan(t *testing.T) {
28 | require.False(t, ParsedVersion{0, 200}.LessThan(ParsedVersion{0, 200}))
29 | require.False(t, ParsedVersion{1, 200}.LessThan(ParsedVersion{1, 200}))
30 | require.False(t, ParsedVersion{0, 201}.LessThan(ParsedVersion{0, 200}))
31 | require.False(t, ParsedVersion{1, 0}.LessThan(ParsedVersion{0, 200}))
32 | require.True(t, ParsedVersion{0, 199}.LessThan(ParsedVersion{0, 200}))
33 | require.True(t, ParsedVersion{0, 200}.LessThan(ParsedVersion{0, 205}))
34 | require.True(t, ParsedVersion{1, 200}.LessThan(ParsedVersion{1, 205}))
35 | require.True(t, ParsedVersion{0, 200}.LessThan(ParsedVersion{1, 1}))
36 | }
37 |
38 | func TestVersionGreaterThan(t *testing.T) {
39 | require.False(t, ParsedVersion{0, 200}.GreaterThan(ParsedVersion{0, 200}))
40 | require.False(t, ParsedVersion{1, 200}.GreaterThan(ParsedVersion{1, 200}))
41 | require.True(t, ParsedVersion{0, 201}.GreaterThan(ParsedVersion{0, 200}))
42 | require.True(t, ParsedVersion{1, 0}.GreaterThan(ParsedVersion{0, 200}))
43 | require.True(t, ParsedVersion{1, 1}.GreaterThan(ParsedVersion{1, 0}))
44 | require.False(t, ParsedVersion{0, 199}.GreaterThan(ParsedVersion{0, 200}))
45 | require.False(t, ParsedVersion{0, 200}.GreaterThan(ParsedVersion{0, 205}))
46 | require.False(t, ParsedVersion{1, 200}.GreaterThan(ParsedVersion{1, 205}))
47 | require.False(t, ParsedVersion{0, 200}.GreaterThan(ParsedVersion{1, 1}))
48 | }
49 |
--------------------------------------------------------------------------------