tabby-quick-snips 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +167 -0
- package/dist/config.d.ts +26 -0
- package/dist/decorator.d.ts +27 -0
- package/dist/fuzzy.d.ts +3 -0
- package/dist/historyStore.d.ts +23 -0
- package/dist/hotkeys.d.ts +6 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/settings.d.ts +24 -0
- package/dist/terminalState.d.ts +10 -0
- package/dist/types.d.ts +25 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# tabby-quick-snips
|
|
2
|
+
|
|
3
|
+
Manual alias-based quick snippets plugin for [Tabby Terminal](https://tabby.sh).
|
|
4
|
+
|
|
5
|
+
This plugin runs on the Tabby UI side and shows a small suggestion overlay inside the terminal. It does not depend on the remote shell. Commands are defined manually by the user and matched with fuzzy search or short aliases such as `ps`, `reset`, or `db-update`.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Client-side autocomplete inside Tabby UI
|
|
10
|
+
- Manual command list management
|
|
11
|
+
- Alias/shortcut support via `shortcut` or `normalized`
|
|
12
|
+
- Fuzzy search like `ps` -> `docker compose ps`
|
|
13
|
+
- Inline dropdown overlay inside the terminal
|
|
14
|
+
- Keyboard navigation with `ArrowUp` and `ArrowDown`
|
|
15
|
+
- Accept suggestion with `Tab`
|
|
16
|
+
- Pin, edit, delete, import, and export entries
|
|
17
|
+
- Settings tab inside Tabby for managing entries
|
|
18
|
+
|
|
19
|
+
## File structure
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
tabby-quick-snips/
|
|
23
|
+
├── src/
|
|
24
|
+
│ ├── config.ts
|
|
25
|
+
│ ├── decorator.ts
|
|
26
|
+
│ ├── fuzzy.ts
|
|
27
|
+
│ ├── historyStore.ts
|
|
28
|
+
│ ├── hotkeys.ts
|
|
29
|
+
│ ├── index.ts
|
|
30
|
+
│ ├── settings.ts
|
|
31
|
+
│ ├── terminalState.ts
|
|
32
|
+
│ └── types.ts
|
|
33
|
+
├── LICENSE
|
|
34
|
+
├── package.json
|
|
35
|
+
├── README.md
|
|
36
|
+
├── tsconfig.json
|
|
37
|
+
└── webpack.config.js
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## How it works
|
|
41
|
+
|
|
42
|
+
1. You define aliases and commands in the `Quick Snips` settings tab.
|
|
43
|
+
2. In terminal, type a partial alias or command, for example `ps` or `reset`.
|
|
44
|
+
3. Press the configured hotkey to open the suggestion overlay.
|
|
45
|
+
4. Use `ArrowUp` and `ArrowDown` to select a result.
|
|
46
|
+
5. Press `Tab` to insert the selected command.
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
### Local development install
|
|
51
|
+
|
|
52
|
+
1. Clone or copy this plugin into its own folder.
|
|
53
|
+
2. Install dependencies:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm install
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
3. Build the plugin:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm run build
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
4. Load it in Tabby.
|
|
66
|
+
|
|
67
|
+
Typical options:
|
|
68
|
+
|
|
69
|
+
- Symlink or copy the package into Tabby's plugin path.
|
|
70
|
+
- Or start Tabby with:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
TABBY_PLUGINS=/absolute/path/to/plugins tabby
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
If you keep this package in `/absolute/path/to/plugins/tabby-quick-snips`, Tabby can discover it as a standalone plugin package.
|
|
77
|
+
|
|
78
|
+
### Publish to npm later
|
|
79
|
+
|
|
80
|
+
This package is already structured as a standalone npm module:
|
|
81
|
+
|
|
82
|
+
- package name: `tabby-quick-snips`
|
|
83
|
+
- keyword: `tabby-plugin`
|
|
84
|
+
- build output: `dist/index.js`
|
|
85
|
+
|
|
86
|
+
Before publishing, update:
|
|
87
|
+
|
|
88
|
+
- `package.json` author/repository/homepage fields
|
|
89
|
+
- version number
|
|
90
|
+
- compatibility notes for the Tabby version you target
|
|
91
|
+
|
|
92
|
+
Then publish with:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
npm publish --access public
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Example usage
|
|
99
|
+
|
|
100
|
+
The plugin ships with these default entries:
|
|
101
|
+
|
|
102
|
+
```json
|
|
103
|
+
[
|
|
104
|
+
{
|
|
105
|
+
"id": "cmd_6t82mzgvmnj17uvo",
|
|
106
|
+
"command": "docker compose ps",
|
|
107
|
+
"normalized": "ps",
|
|
108
|
+
"pinned": false
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"id": "cmd_6t82mzgvmnj17uv2",
|
|
112
|
+
"command": "docker compose down; docker compose up -d --force-recreate",
|
|
113
|
+
"normalized": "reset",
|
|
114
|
+
"pinned": false
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"id": "cmd_6t82mzgvmnj17uv3",
|
|
118
|
+
"command": "php bin/console doctrine:cache:clear-metadata; php bin/console doctrine:schema:update --force --no-interaction;",
|
|
119
|
+
"normalized": "db-update",
|
|
120
|
+
"pinned": false
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"id": "demo_git_status",
|
|
124
|
+
"command": "git status",
|
|
125
|
+
"normalized": "git status",
|
|
126
|
+
"pinned": true
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
If your list gets messy, open `Quick Snips` settings and click `Reset Defaults`.
|
|
132
|
+
|
|
133
|
+
Then in terminal:
|
|
134
|
+
|
|
135
|
+
1. Type `ps`
|
|
136
|
+
2. Press `Cmd+P`
|
|
137
|
+
3. Choose `docker compose ps`
|
|
138
|
+
4. Press `Tab`
|
|
139
|
+
|
|
140
|
+
Or:
|
|
141
|
+
|
|
142
|
+
1. Type `reset`
|
|
143
|
+
2. Press `Cmd+P`
|
|
144
|
+
3. Press `Tab`
|
|
145
|
+
|
|
146
|
+
## Default behavior
|
|
147
|
+
|
|
148
|
+
- Hotkey: `Cmd+P`
|
|
149
|
+
- Auto show: disabled
|
|
150
|
+
- Minimum typed characters: `2`
|
|
151
|
+
- Suggestions come only from manually saved entries
|
|
152
|
+
- `Enter` does not accept suggestions
|
|
153
|
+
- `Tab` accepts the selected suggestion
|
|
154
|
+
|
|
155
|
+
## Notes
|
|
156
|
+
|
|
157
|
+
- Data is stored in Tabby's local config under `historyAutocomplete`.
|
|
158
|
+
- The visible plugin name in Tabby is `Quick Snips`.
|
|
159
|
+
- `normalized` is treated as the alias trigger value.
|
|
160
|
+
- If `shortcut` exists, it is also used as the alias trigger value.
|
|
161
|
+
- The settings tab is the recommended way to manage entries.
|
|
162
|
+
|
|
163
|
+
## Suggested next improvements
|
|
164
|
+
|
|
165
|
+
- Replace the simple settings form with a cleaner table editor.
|
|
166
|
+
- Add drag-and-drop sorting and sections/groups.
|
|
167
|
+
- Add optional per-profile command sets.
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ConfigProvider } from 'tabby-core';
|
|
2
|
+
import type { CommandHistoryEntry, CommandHistoryStore } from './types';
|
|
3
|
+
export declare const DEFAULT_HISTORY_ENTRIES: CommandHistoryEntry[];
|
|
4
|
+
export declare const DEFAULT_HISTORY_STORE: CommandHistoryStore;
|
|
5
|
+
export declare class HistoryAutocompleteConfigProvider extends ConfigProvider {
|
|
6
|
+
defaults: {
|
|
7
|
+
historyAutocomplete: CommandHistoryStore;
|
|
8
|
+
};
|
|
9
|
+
platformDefaults: {
|
|
10
|
+
macOS: {
|
|
11
|
+
hotkeys: {
|
|
12
|
+
'history-autocomplete.toggle': string[];
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
Windows: {
|
|
16
|
+
hotkeys: {
|
|
17
|
+
'history-autocomplete.toggle': string[];
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
Linux: {
|
|
21
|
+
hotkeys: {
|
|
22
|
+
'history-autocomplete.toggle': string[];
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { BaseTerminalTabComponent, TerminalDecorator } from 'tabby-terminal';
|
|
2
|
+
import { HistoryAutocompleteStore } from './historyStore';
|
|
3
|
+
export declare class HistoryAutocompleteDecorator extends TerminalDecorator {
|
|
4
|
+
private historyStore;
|
|
5
|
+
private sessions;
|
|
6
|
+
constructor(historyStore: HistoryAutocompleteStore);
|
|
7
|
+
attach(terminal: BaseTerminalTabComponent<any>): void;
|
|
8
|
+
private attachUi;
|
|
9
|
+
private onKeyDown;
|
|
10
|
+
private refreshSuggestions;
|
|
11
|
+
private render;
|
|
12
|
+
private makeFooterButton;
|
|
13
|
+
private acceptSelection;
|
|
14
|
+
private togglePinSelection;
|
|
15
|
+
private deleteSelection;
|
|
16
|
+
private editSelection;
|
|
17
|
+
private exportHistory;
|
|
18
|
+
private addEntry;
|
|
19
|
+
private importHistory;
|
|
20
|
+
private hide;
|
|
21
|
+
private sendInput;
|
|
22
|
+
private highlight;
|
|
23
|
+
private escapeHtml;
|
|
24
|
+
private relativeTime;
|
|
25
|
+
private matchesHotkey;
|
|
26
|
+
private getProfileId;
|
|
27
|
+
}
|
package/dist/fuzzy.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { SuggestionResult, CommandHistoryEntry } from './types';
|
|
2
|
+
export declare function fuzzyScore(query: string, command: string): SuggestionResult | null;
|
|
3
|
+
export declare function rankHistory(query: string, entries: CommandHistoryEntry[], limit?: number): SuggestionResult[];
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ConfigService } from 'tabby-core';
|
|
2
|
+
import { CommandHistoryEntry, CommandHistoryStore, SuggestionResult } from './types';
|
|
3
|
+
export declare class HistoryAutocompleteStore {
|
|
4
|
+
private config;
|
|
5
|
+
constructor(config: ConfigService);
|
|
6
|
+
private normalizeCommand;
|
|
7
|
+
private normalizeShortcut;
|
|
8
|
+
getStore(): CommandHistoryStore;
|
|
9
|
+
addManualEntry(command: string, profileId?: string | null, pinned?: boolean): Promise<void>;
|
|
10
|
+
getSuggestions(query: string, profileId?: string | null): SuggestionResult[];
|
|
11
|
+
pinEntry(entryId: string, pinned: boolean): Promise<void>;
|
|
12
|
+
deleteEntry(entryId: string): Promise<void>;
|
|
13
|
+
updateEntryCommand(entryId: string, command: string): Promise<void>;
|
|
14
|
+
exportJson(): string;
|
|
15
|
+
importJson(json: string): Promise<void>;
|
|
16
|
+
saveSettings(settings: Partial<Pick<CommandHistoryStore, 'hotkey' | 'autoShow' | 'maxEntries' | 'minChars' | 'scope'>>, entries?: CommandHistoryEntry[]): Promise<void>;
|
|
17
|
+
resetToDefaults(): Promise<void>;
|
|
18
|
+
private normalizeEntries;
|
|
19
|
+
private filterEntries;
|
|
20
|
+
private trimEntries;
|
|
21
|
+
private persist;
|
|
22
|
+
private makeId;
|
|
23
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(()=>{"use strict";var e={28(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.HistoryAutocompleteConfigProvider=t.DEFAULT_HISTORY_STORE=t.DEFAULT_HISTORY_ENTRIES=void 0;const s=n(368);t.DEFAULT_HISTORY_ENTRIES=[{id:"cmd_6t82mzgvmnj17uvo",command:"docker compose ps",normalized:"ps",shortcut:"ps",pinned:!1,count:4,createdAt:"2026-04-03T15:01:47.412Z",lastUsedAt:"2026-04-03T15:13:24.152Z",profileIds:["local:default"]},{id:"cmd_6t82mzgvmnj17uv2",command:"docker compose down; docker compose up -d --force-recreate",normalized:"reset",shortcut:"reset",pinned:!1,count:4,createdAt:"2026-04-03T15:01:47.412Z",lastUsedAt:"2026-04-03T15:13:24.152Z",profileIds:["local:default"]},{id:"cmd_6t82mzgvmnj17uv3",command:"php bin/console doctrine:cache:clear-metadata; php bin/console doctrine:schema:update --force --no-interaction;",normalized:"db-update",shortcut:"db-update",pinned:!1,count:4,createdAt:"2026-04-03T15:01:47.412Z",lastUsedAt:"2026-04-03T15:13:24.152Z",profileIds:["local:default"]},{id:"demo_git_status",command:"git status",normalized:"git status",shortcut:"git status",pinned:!0,count:3,lastUsedAt:"2026-04-03T14:30:00.000Z",createdAt:"2026-04-03T14:30:00.000Z",profileIds:[]}],t.DEFAULT_HISTORY_STORE={version:1,scope:"both",maxEntries:2e3,autoShow:!1,minChars:2,hotkey:"Cmd-P",entries:t.DEFAULT_HISTORY_ENTRIES};class r extends s.ConfigProvider{constructor(){super(...arguments),this.defaults={historyAutocomplete:t.DEFAULT_HISTORY_STORE},this.platformDefaults={[s.Platform.macOS]:{hotkeys:{"history-autocomplete.toggle":["Cmd-P"]}},[s.Platform.Windows]:{hotkeys:{"history-autocomplete.toggle":["Cmd-P"]}},[s.Platform.Linux]:{hotkeys:{"history-autocomplete.toggle":["Cmd-P"]}}}}}t.HistoryAutocompleteConfigProvider=r},9(e,t,n){var s=this&&this.__decorate||function(e,t,n,s){var r,o=arguments.length,i=o<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,n):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,n,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(i=(o<3?r(i):o>3?r(t,n,i):r(t,n))||i);return o>3&&i&&Object.defineProperty(t,n,i),i},r=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)};Object.defineProperty(t,"__esModule",{value:!0}),t.HistoryAutocompleteDecorator=void 0;const o=n(430),i=n(319),a=n(859),c=n(621);let l=class extends i.TerminalDecorator{constructor(e){super(),this.historyStore=e,this.sessions=new WeakMap}attach(e){setTimeout(()=>this.attachUi(e)),e.destroyed$?.subscribe&&this.subscribeUntilDetached(e,e.destroyed$.subscribe(()=>{this.hide(e)}))}attachUi(e){const t=e.element?.nativeElement,n=e.content?.nativeElement??t;if(!n||this.sessions.has(e))return;"static"===getComputedStyle(n).position&&(n.style.position="relative");const s=document.createElement("div");s.className="history-autocomplete-overlay",s.style.cssText=["position:absolute","left:12px","right:12px","bottom:18px","z-index:30","display:none","background:#111827","color:#e5e7eb","border:1px solid rgba(255,255,255,0.08)","border-radius:10px","box-shadow:0 18px 40px rgba(0,0,0,0.45)","backdrop-filter: blur(12px)","overflow:hidden","font-family: ui-monospace, SFMono-Regular, Menlo, monospace","pointer-events:auto","max-width:min(720px, calc(100% - 24px))"].join(";");const r=document.createElement("div");r.style.cssText="max-height:260px;overflow:auto";const o=document.createElement("div");o.style.cssText=["display:flex","justify-content:space-between","gap:12px","padding:8px 12px","font-size:11px","color:#9ca3af","border-top:1px solid rgba(255,255,255,0.08)","background:rgba(255,255,255,0.02)"].join(";"),s.append(r,o),n.appendChild(s);const i=document.createElement("input");i.type="file",i.accept="application/json",i.style.display="none",n.appendChild(i);const a={host:n,keyTarget:t??n,overlay:s,list:r,footer:o,importInput:i,state:new c.TerminalInputState,suggestions:[],selectedIndex:0,visible:!1,manuallyOpened:!1};this.sessions.set(e,a),a.keyTarget.addEventListener("keydown",t=>this.onKeyDown(e,t),!0),i.addEventListener("change",()=>this.importHistory(e))}onKeyDown(e,t){const n=this.sessions.get(e);if(!n)return;if(this.matchesHotkey(e,t))return t.preventDefault(),t.stopPropagation(),n.manuallyOpened=!n.visible,void this.refreshSuggestions(e,n.state.getCurrentLine(),n.manuallyOpened);const s=n.state.applyKeydown(t);if(n.visible){if(n.manuallyOpened){if("ArrowDown"===t.key)return t.preventDefault(),n.selectedIndex=(n.selectedIndex+1)%Math.max(1,n.suggestions.length),void this.render(e);if("ArrowUp"===t.key)return t.preventDefault(),n.selectedIndex=(n.selectedIndex-1+Math.max(1,n.suggestions.length))%Math.max(1,n.suggestions.length),void this.render(e);if("Tab"===t.key){if(0===n.suggestions.length)return;return t.preventDefault(),t.stopPropagation(),void this.acceptSelection(e)}return"Escape"===t.key?(t.preventDefault(),void this.hide(e)):"Enter"===t.key?(this.hide(e),void n.state.setCurrentLine("")):"Delete"===t.key&&n.suggestions.length?(t.preventDefault(),void this.deleteSelection(e)):t.ctrlKey&&"p"===t.key.toLowerCase()&&n.suggestions.length?(t.preventDefault(),void this.togglePinSelection(e)):t.ctrlKey&&"e"===t.key.toLowerCase()&&n.suggestions.length?(t.preventDefault(),void this.editSelection(e)):void queueMicrotask(()=>{n.visible&&n.manuallyOpened&&this.refreshSuggestions(e,s,!0)})}}else"Enter"===t.key&&n.state.setCurrentLine("")}refreshSuggestions(e,t,n=!1){const s=this.sessions.get(e);if(!s)return;const r=s.manuallyOpened?t:t.trim();s.suggestions=this.historyStore.getSuggestions(r,this.getProfileId(e)),s.selectedIndex=Math.min(s.selectedIndex,Math.max(0,s.suggestions.length-1)),s.visible=n||s.suggestions.length>0,s.visible&&0!==s.suggestions.length||s.manuallyOpened&&t.trim().length>0&&(s.suggestions=this.historyStore.getSuggestions("",this.getProfileId(e)),s.selectedIndex=Math.min(s.selectedIndex,Math.max(0,s.suggestions.length-1)),s.visible=s.suggestions.length>0),s.visible&&0!==s.suggestions.length?(s.overlay.style.display="block",this.render(e)):this.hide(e)}render(e){const t=this.sessions.get(e);if(!t)return;t.list.innerHTML="",t.suggestions.forEach((n,s)=>{const r=document.createElement("div");r.style.cssText=["display:flex","align-items:center","gap:10px","padding:9px 12px","cursor:pointer","border-bottom:1px solid rgba(255,255,255,0.04)",s===t.selectedIndex?"background:rgba(59,130,246,0.22)":"background:transparent"].join(";");const o=document.createElement("div");o.textContent=n.entry.pinned?"★":"↳",o.style.cssText="width:18px;color:#93c5fd;flex:0 0 auto";const i=document.createElement("div");i.style.cssText="display:flex;flex-direction:column;min-width:0;flex:1 1 auto";const a=document.createElement("div");a.style.cssText="white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:13px",a.innerHTML=this.highlight(n.entry.command,n.highlights);const c=document.createElement("div");c.style.cssText="font-size:11px;color:#9ca3af";const l=n.entry.shortcut?.trim();c.textContent=l&&l!==n.entry.command.trim().toLowerCase()?`${l} • ${n.entry.count}x used • ${this.relativeTime(n.entry.lastUsedAt)}`:`${n.entry.count}x used • ${this.relativeTime(n.entry.lastUsedAt)}`,i.append(a,c),r.append(o,i),r.addEventListener("mouseenter",()=>{t.selectedIndex=s,this.render(e)}),r.addEventListener("mousedown",n=>{n.preventDefault(),t.selectedIndex=s,this.acceptSelection(e)}),t.list.appendChild(r)}),t.footer.innerHTML="";const n=document.createElement("div");n.textContent="↑↓ navigate • Tab apply • Del remove • Ctrl+P pin • Ctrl+E edit";const s=document.createElement("div");s.style.cssText="display:flex;gap:10px",s.appendChild(this.makeFooterButton("Add",()=>{this.addEntry(e)})),s.appendChild(this.makeFooterButton("Export",()=>this.exportHistory())),s.appendChild(this.makeFooterButton("Import",()=>t.importInput.click())),t.footer.append(n,s)}makeFooterButton(e,t){const n=document.createElement("button");return n.type="button",n.textContent=e,n.style.cssText=["background:transparent","border:none","color:#cbd5e1","cursor:pointer","padding:0","font-size:11px"].join(";"),n.addEventListener("mousedown",e=>e.preventDefault()),n.addEventListener("click",t),n}async acceptSelection(e){const t=this.sessions.get(e);if(!t)return;const n=t.suggestions[t.selectedIndex];if(!n)return;const s=t.state.getCurrentLine(),r=n.entry.command,o=s.trim().toLowerCase(),i=r.toLowerCase();if(o&&i.startsWith(o)){const t=r.slice(s.length);this.sendInput(e,t)}else this.sendInput(e,""),this.sendInput(e,r);t.state.setCurrentLine(r),this.hide(e)}async togglePinSelection(e){const t=this.sessions.get(e),n=t?.suggestions[t.selectedIndex];n&&(await this.historyStore.pinEntry(n.entry.id,!n.entry.pinned),this.refreshSuggestions(e,t?.state.getCurrentLine()??"",!0))}async deleteSelection(e){const t=this.sessions.get(e),n=t?.suggestions[t.selectedIndex];n&&(await this.historyStore.deleteEntry(n.entry.id),this.refreshSuggestions(e,t?.state.getCurrentLine()??"",!0))}async editSelection(e){const t=this.sessions.get(e),n=t?.suggestions[t.selectedIndex];if(!n)return;const s=window.prompt("Edit command history entry",n.entry.command);s?.trim()&&(await this.historyStore.updateEntryCommand(n.entry.id,s),this.refreshSuggestions(e,t?.state.getCurrentLine()??"",!0))}exportHistory(){const e=new Blob([this.historyStore.exportJson()],{type:"application/json"}),t=URL.createObjectURL(e),n=document.createElement("a");n.href=t,n.download="tabby-quick-snips.json",n.click(),URL.revokeObjectURL(t)}async addEntry(e){const t=this.sessions.get(e),n=t?.state.getCurrentLine()??"",s=window.prompt("Add command to history",n);s?.trim()&&(await this.historyStore.addManualEntry(s,this.getProfileId(e)),t&&(t.manuallyOpened=!0),this.refreshSuggestions(e,s,!0))}async importHistory(e){const t=this.sessions.get(e),n=t?.importInput.files?.[0];if(!n)return;const s=await n.text();await this.historyStore.importJson(s),t.importInput.value="",this.refreshSuggestions(e,t?.state.getCurrentLine()??"",!0)}hide(e){const t=this.sessions.get(e);t&&(t.visible=!1,t.manuallyOpened=!1,t.overlay.style.display="none")}sendInput(e,t){const n=e.sendInput;"function"==typeof n&&n.call(e,Buffer.from(t))}highlight(e,t){const n=new Set(t);return Array.from(e).map((e,t)=>n.has(t)?`<span style="color:#ffffff;font-weight:700">${this.escapeHtml(e)}</span>`:`<span style="color:#cbd5e1">${this.escapeHtml(e)}</span>`).join("")}escapeHtml(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}relativeTime(e){const t=Date.now()-Date.parse(e),n=Math.floor(t/6e4);if(n<1)return"just now";if(n<60)return`${n}m ago`;const s=Math.floor(n/60);return s<24?`${s}h ago`:`${Math.floor(s/24)}d ago`}matchesHotkey(e,t){const n=(this.historyStore.getStore().hotkey||"Ctrl-Space").toLowerCase().split("-"),s="space"===n[n.length-1]?" ":n[n.length-1],r=n.includes("ctrl"),o=n.includes("alt"),i=n.includes("shift"),a=n.includes("meta")||n.includes("cmd");return t.key.toLowerCase()===s&&t.ctrlKey===r&&t.altKey===o&&t.shiftKey===i&&t.metaKey===a}getProfileId(e){const t=e.profile;return t?.id??t?.name??null}};t.HistoryAutocompleteDecorator=l,t.HistoryAutocompleteDecorator=l=s([(0,o.Injectable)(),r("design:paramtypes",[a.HistoryAutocompleteStore])],l)},324(e,t){function n(e){return e.trim().toLowerCase()}function s(e,t){if(0===t)return 10;const n=e[t-1];return/[\s:/._-]/.test(n)?6:0}function r(e,t){const r=n(e),o=n(t);if(!r)return{entry:null,score:0,highlights:[]};let i=0,a=0,c=0;const l=[];for(let e=0;e<o.length;e++)if(o[e]===r[i]){if(l.push(e),a+=4+s(o,e),e===i&&(a+=8),c>0&&(a+=5*c),c++,i++,i===r.length)return a+=Math.max(0,12-(e-l[0])),a+=o.startsWith(r)?20:0,a+=o.includes(` ${r}`)?8:0,{entry:null,score:a,highlights:l}}else c=0;return null}Object.defineProperty(t,"__esModule",{value:!0}),t.fuzzyScore=r,t.rankHistory=function(e,t,n=8){const s=e.trim().toLowerCase();return s?t.map(e=>{const t=r(s,e.command),n=e.shortcut?.trim()||e.normalized,o=n?r(s,n):null;if(!t&&!o)return null;const i=o?t?o.score>=t.score?o:t:o:t,a=Math.max(0,Math.min(20,e.count+Math.floor((Date.now()-Date.parse(e.lastUsedAt))/-864e5)));return{entry:e,score:i.score+(e.pinned?30:0)+a,highlights:i.highlights}}).filter(e=>Boolean(e)).sort((e,t)=>e.entry.pinned!==t.entry.pinned?Number(t.entry.pinned)-Number(e.entry.pinned):e.score!==t.score?t.score-e.score:Date.parse(t.entry.lastUsedAt)-Date.parse(e.entry.lastUsedAt)).slice(0,n):t.slice().sort((e,t)=>e.pinned!==t.pinned?Number(t.pinned)-Number(e.pinned):Date.parse(t.lastUsedAt)-Date.parse(e.lastUsedAt)).slice(0,n).map(e=>({entry:e,score:e.pinned?1e3:0,highlights:[]}))}},859(e,t,n){var s=this&&this.__decorate||function(e,t,n,s){var r,o=arguments.length,i=o<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,n):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,n,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(i=(o<3?r(i):o>3?r(t,n,i):r(t,n))||i);return o>3&&i&&Object.defineProperty(t,n,i),i},r=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)};Object.defineProperty(t,"__esModule",{value:!0}),t.HistoryAutocompleteStore=void 0;const o=n(430),i=n(368),a=n(28),c=n(324);let l=class{constructor(e){this.config=e}normalizeCommand(e){return e.trim().toLowerCase()}normalizeShortcut(e,t){const n=e?.trim().toLowerCase();return n||this.normalizeCommand(t)}getStore(){const e=this.config.store?.historyAutocomplete??{},t=Array.isArray(e.entries)&&e.entries.length?e.entries:a.DEFAULT_HISTORY_ENTRIES;return{...a.DEFAULT_HISTORY_STORE,...e,entries:this.normalizeEntries(t,e.maxEntries??a.DEFAULT_HISTORY_STORE.maxEntries)}}async addManualEntry(e,t,n=!1){const s=e.trim();if(!s)return;const r=this.getStore(),o=this.normalizeCommand(s),i=(new Date).toISOString(),a=r.entries.find(e=>this.normalizeCommand(e.command)===o);a?(a.command=s,a.pinned=a.pinned||n,a.lastUsedAt=i,t&&!a.profileIds.includes(t)&&a.profileIds.push(t)):r.entries.unshift({id:this.makeId(),command:s,normalized:o,shortcut:o,pinned:n,count:1,createdAt:i,lastUsedAt:i,profileIds:t?[t]:[]}),r.entries=this.trimEntries(r.entries,r.maxEntries),await this.persist(r)}getSuggestions(e,t){const n=this.getStore(),s=this.filterEntries(n,t);return(0,c.rankHistory)(e,s)}async pinEntry(e,t){const n=this.getStore(),s=n.entries.find(t=>t.id===e);s&&(s.pinned=t,await this.persist(n))}async deleteEntry(e){const t=this.getStore();t.entries=t.entries.filter(t=>t.id!==e),await this.persist(t)}async updateEntryCommand(e,t){const n=this.getStore(),s=n.entries.find(t=>t.id===e);s&&(s.command=t.trim(),s.normalized=this.normalizeShortcut(s.shortcut,s.command),s.lastUsedAt=(new Date).toISOString(),await this.persist(n))}exportJson(){return JSON.stringify(this.getStore(),null,2)}async importJson(e){const t=JSON.parse(e),n={...a.DEFAULT_HISTORY_STORE,...t,entries:Array.isArray(t.entries)?t.entries:[]};n.entries=this.trimEntries(n.entries,n.maxEntries).map(e=>({...e,normalized:this.normalizeShortcut(e.shortcut??e.normalized,e.command),shortcut:this.normalizeShortcut(e.shortcut??e.normalized,e.command),profileIds:Array.isArray(e.profileIds)?e.profileIds:[],pinned:Boolean(e.pinned),count:Math.max(1,e.count??1),createdAt:e.createdAt??(new Date).toISOString(),lastUsedAt:e.lastUsedAt??(new Date).toISOString()})),await this.persist(n)}async saveSettings(e,t){const n=this.getStore(),s={...n,...e,entries:t?this.normalizeEntries(t,e.maxEntries??n.maxEntries):n.entries};await this.persist(s)}async resetToDefaults(){await this.persist({...a.DEFAULT_HISTORY_STORE,entries:this.normalizeEntries(a.DEFAULT_HISTORY_ENTRIES,a.DEFAULT_HISTORY_STORE.maxEntries)})}normalizeEntries(e,t){return this.trimEntries(e,t).map(e=>({...e,id:e.id||this.makeId(),command:e.command.trim(),normalized:this.normalizeShortcut(e.shortcut??e.normalized,e.command),shortcut:this.normalizeShortcut(e.shortcut??e.normalized,e.command),pinned:Boolean(e.pinned),count:Math.max(1,e.count??1),createdAt:e.createdAt??(new Date).toISOString(),lastUsedAt:e.lastUsedAt??(new Date).toISOString(),profileIds:Array.isArray(e.profileIds)?e.profileIds:[]})).filter(e=>e.command)}filterEntries(e,t){return"global"===e.scope?e.entries:"profile"===e.scope&&t?e.entries.filter(e=>e.profileIds.includes(t)):(e.scope,e.entries)}trimEntries(e,t){return[...e.filter(e=>e.pinned),...e.filter(e=>!e.pinned).sort((e,t)=>Date.parse(t.lastUsedAt)-Date.parse(e.lastUsedAt))].slice(0,t)}async persist(e){this.config.store.historyAutocomplete.hotkey=e.hotkey,this.config.store.historyAutocomplete.autoShow=e.autoShow,this.config.store.historyAutocomplete.maxEntries=e.maxEntries,this.config.store.historyAutocomplete.minChars=e.minChars,this.config.store.historyAutocomplete.scope=e.scope,this.config.store.historyAutocomplete.entries=this.normalizeEntries(e.entries,e.maxEntries),await this.config.save()}makeId(){return`cmd_${Math.random().toString(36).slice(2,10)}${Date.now().toString(36)}`}};t.HistoryAutocompleteStore=l,t.HistoryAutocompleteStore=l=s([(0,o.Injectable)(),r("design:paramtypes",[i.ConfigService])],l)},771(e,t,n){var s=this&&this.__decorate||function(e,t,n,s){var r,o=arguments.length,i=o<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,n):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,n,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(i=(o<3?r(i):o>3?r(t,n,i):r(t,n))||i);return o>3&&i&&Object.defineProperty(t,n,i),i},r=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)};Object.defineProperty(t,"__esModule",{value:!0}),t.HistoryAutocompleteHotkeyProvider=void 0;const o=n(430),i=n(368);let a=class extends i.HotkeyProvider{constructor(){super(),this.hotkeys=[{id:"history-autocomplete.toggle",name:"Show command history suggestions"}]}async provide(){return this.hotkeys}};t.HistoryAutocompleteHotkeyProvider=a,t.HistoryAutocompleteHotkeyProvider=a=s([(0,o.Injectable)(),r("design:paramtypes",[])],a)},156(e,t,n){var s=this&&this.__decorate||function(e,t,n,s){var r,o=arguments.length,i=o<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,n):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,n,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(i=(o<3?r(i):o>3?r(t,n,i):r(t,n))||i);return o>3&&i&&Object.defineProperty(t,n,i),i};Object.defineProperty(t,"__esModule",{value:!0});const r=n(804),o=n(430),i=n(368),a=n(319),c=n(262),l=n(28),d=n(9),p=n(859),u=n(771),h=n(451);let m=class{};m=s([(0,o.NgModule)({declarations:[h.HistoryAutocompleteSettingsComponent],imports:[r.CommonModule],providers:[p.HistoryAutocompleteStore,{provide:a.TerminalDecorator,useClass:d.HistoryAutocompleteDecorator,multi:!0},{provide:i.ConfigProvider,useClass:l.HistoryAutocompleteConfigProvider,multi:!0},{provide:i.HotkeyProvider,useClass:u.HistoryAutocompleteHotkeyProvider,multi:!0},{provide:c.SettingsTabProvider,useClass:h.HistoryAutocompleteSettingsTabProvider,multi:!0}]})],m),t.default=m},451(e,t,n){var s=this&&this.__decorate||function(e,t,n,s){var r,o=arguments.length,i=o<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,n):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,n,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(i=(o<3?r(i):o>3?r(t,n,i):r(t,n))||i);return o>3&&i&&Object.defineProperty(t,n,i),i},r=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)};Object.defineProperty(t,"__esModule",{value:!0}),t.HistoryAutocompleteSettingsTabProvider=t.HistoryAutocompleteSettingsComponent=void 0;const o=n(430),i=n(262),a=n(859);let c=class{constructor(e){this.store=e,this.hotkey="Cmd-P",this.autoShow=!1,this.editableEntries=[],this.message="",this.reload()}any(e){return e}reload(){const e=this.store.getStore();this.hotkey=e.hotkey,this.autoShow=e.autoShow,this.editableEntries=e.entries.map(e=>({...e})),this.message=""}async save(){try{await this.store.saveSettings({hotkey:this.hotkey.trim()||"Cmd-P",autoShow:this.autoShow},this.editableEntries),this.message="Saved",this.reload()}catch(e){this.message=`Save failed: ${e?.message??"Unknown error"}`}}async resetDefaults(){try{await this.store.resetToDefaults(),this.message="Defaults restored",this.reload()}catch(e){this.message=`Reset failed: ${e?.message??"Unknown error"}`}}addEmptyEntry(){this.editableEntries=[...this.editableEntries,{id:"",command:"",normalized:"",shortcut:"",pinned:!1,count:1,createdAt:(new Date).toISOString(),lastUsedAt:(new Date).toISOString(),profileIds:[]}]}removeEntry(e){this.editableEntries=this.editableEntries.filter((t,n)=>n!==e)}updateEntry(e,t,n){this.editableEntries=this.editableEntries.map((s,r)=>r===e?{...s,[t]:n}:s)}};t.HistoryAutocompleteSettingsComponent=c,t.HistoryAutocompleteSettingsComponent=c=s([(0,o.Component)({selector:"quick-snips-settings",template:'\n <div class="content-box" style="padding: 24px; max-width: 900px;">\n <h2 style="margin-top: 0;">Quick Snips</h2>\n <p style="opacity: .8;">This plugin now uses only manual entries that you define here.</p>\n\n <div style="display:grid;grid-template-columns:180px minmax(0,1fr);gap:12px 16px;align-items:center;margin-bottom:20px;">\n <label>Hotkey</label>\n <input [value]="hotkey" (input)="hotkey = any($event.target).value" style="width: 220px;" />\n\n <label>Auto show</label>\n <input type="checkbox" [checked]="autoShow" (change)="autoShow = any($event.target).checked" />\n </div>\n\n <div style="display:flex;gap:8px;align-items:center;margin-bottom:10px;">\n <button\n type="button"\n (click)="addEmptyEntry()"\n style="background:#315efb;color:#fff;border:none;border-radius:8px;padding:8px 12px;cursor:pointer;"\n >Add Row</button>\n <button\n type="button"\n (click)="resetDefaults()"\n style="background:transparent;color:#fff;border:1px solid rgba(255,255,255,.25);border-radius:8px;padding:8px 12px;cursor:pointer;"\n >Reset Defaults</button>\n <span style="opacity:.75">Use Alias as the trigger text, then press Tab in terminal.</span>\n </div>\n\n <div style="margin-bottom:12px;opacity:.8;">Entries: {{ editableEntries.length }}</div>\n\n <div style="display:grid;grid-template-columns:180px minmax(0,1fr) 80px 90px;gap:8px;align-items:center;margin-bottom:8px;font-weight:600;opacity:.85;">\n <div>Alias</div>\n <div>Command</div>\n <div>Pinned</div>\n <div></div>\n </div>\n\n <div *ngFor="let entry of editableEntries; let i = index" style="display:grid;grid-template-columns:180px minmax(0,1fr) 80px 90px;gap:8px;align-items:center;margin-bottom:8px;">\n <input [value]="entry.shortcut || entry.normalized" (input)="updateEntry(i, \'shortcut\', any($event.target).value)" />\n <input [value]="entry.command" (input)="updateEntry(i, \'command\', any($event.target).value)" />\n <input type="checkbox" [checked]="entry.pinned" (change)="updateEntry(i, \'pinned\', any($event.target).checked)" />\n <button\n type="button"\n (click)="removeEntry(i)"\n style="background:transparent;color:#fff;border:1px solid rgba(255,255,255,.25);border-radius:8px;padding:8px 12px;cursor:pointer;"\n >Delete</button>\n </div>\n\n <div *ngIf="editableEntries.length === 0" style="margin:16px 0;opacity:.7;">\n No entries yet. Click <strong>Add Row</strong> to create one.\n </div>\n\n <div style="display:flex;gap:10px;align-items:center;margin-top:12px;">\n <button\n type="button"\n (click)="save()"\n style="background:#315efb;color:#fff;border:none;border-radius:8px;padding:8px 14px;cursor:pointer;"\n >Save</button>\n <button\n type="button"\n (click)="reload()"\n style="background:transparent;color:#fff;border:1px solid rgba(255,255,255,.25);border-radius:8px;padding:8px 14px;cursor:pointer;"\n >Reload</button>\n <span style="opacity:.8">{{ message }}</span>\n </div>\n </div>\n '}),r("design:paramtypes",[a.HistoryAutocompleteStore])],c);let l=class extends i.SettingsTabProvider{constructor(){super(...arguments),this.id="quick-snips",this.icon="keyboard",this.title="Quick Snips"}getComponentType(){return c}};t.HistoryAutocompleteSettingsTabProvider=l,t.HistoryAutocompleteSettingsTabProvider=l=s([(0,o.Injectable)()],l)},621(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.TerminalInputState=void 0,t.TerminalInputState=class{constructor(){this.currentLine=""}applyInput(e){const t=Array.from(e);let n;for(const e of t){const t=e.charCodeAt(0);"\r"!==e&&"\n"!==e?3!==t&&4!==t&&12!==t&&21!==t?23!==t?127!==t&&8!==t?t<32||127===t||(this.currentLine+=e):this.currentLine=this.currentLine.slice(0,-1):this.currentLine=this.currentLine.replace(/\s*\S+\s*$/,""):this.currentLine="":(n=this.currentLine.trim(),this.currentLine="")}return{commandToStore:n,currentLine:this.currentLine}}getCurrentLine(){return this.currentLine}setCurrentLine(e){this.currentLine=e}applyKeydown(e){return e.metaKey||e.altKey?this.currentLine:e.ctrlKey?("u"===e.key.toLowerCase()?this.currentLine="":"w"===e.key.toLowerCase()&&(this.currentLine=this.currentLine.replace(/\s*\S+\s*$/,"")),this.currentLine):"Backspace"===e.key?(this.currentLine=this.currentLine.slice(0,-1),this.currentLine):("Delete"===e.key||"Enter"===e.key||"Tab"===e.key||e.key.startsWith("Arrow")||"Escape"===e.key||1===e.key.length&&(this.currentLine+=e.key),this.currentLine)}}},804(e){e.exports=require("@angular/common")},430(e){e.exports=require("@angular/core")},368(e){e.exports=require("tabby-core")},262(e){e.exports=require("tabby-settings")},319(e){e.exports=require("tabby-terminal")}},t={},n=function n(s){var r=t[s];if(void 0!==r)return r.exports;var o=t[s]={exports:{}};return e[s].call(o.exports,o,o.exports,n),o.exports}(156);module.exports=n})();
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { SettingsTabProvider } from 'tabby-settings';
|
|
2
|
+
import { HistoryAutocompleteStore } from './historyStore';
|
|
3
|
+
import type { CommandHistoryEntry } from './types';
|
|
4
|
+
export declare class HistoryAutocompleteSettingsComponent {
|
|
5
|
+
private store;
|
|
6
|
+
hotkey: string;
|
|
7
|
+
autoShow: boolean;
|
|
8
|
+
editableEntries: CommandHistoryEntry[];
|
|
9
|
+
message: string;
|
|
10
|
+
constructor(store: HistoryAutocompleteStore);
|
|
11
|
+
any(value: EventTarget | null): any;
|
|
12
|
+
reload(): void;
|
|
13
|
+
save(): Promise<void>;
|
|
14
|
+
resetDefaults(): Promise<void>;
|
|
15
|
+
addEmptyEntry(): void;
|
|
16
|
+
removeEntry(index: number): void;
|
|
17
|
+
updateEntry(index: number, field: keyof CommandHistoryEntry, value: any): void;
|
|
18
|
+
}
|
|
19
|
+
export declare class HistoryAutocompleteSettingsTabProvider extends SettingsTabProvider {
|
|
20
|
+
id: string;
|
|
21
|
+
icon: string;
|
|
22
|
+
title: string;
|
|
23
|
+
getComponentType(): any;
|
|
24
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare class TerminalInputState {
|
|
2
|
+
private currentLine;
|
|
3
|
+
applyInput(chunk: string): {
|
|
4
|
+
commandToStore?: string;
|
|
5
|
+
currentLine: string;
|
|
6
|
+
};
|
|
7
|
+
getCurrentLine(): string;
|
|
8
|
+
setCurrentLine(value: string): void;
|
|
9
|
+
applyKeydown(event: KeyboardEvent): string;
|
|
10
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface CommandHistoryEntry {
|
|
2
|
+
id: string;
|
|
3
|
+
command: string;
|
|
4
|
+
normalized: string;
|
|
5
|
+
shortcut?: string;
|
|
6
|
+
pinned: boolean;
|
|
7
|
+
count: number;
|
|
8
|
+
lastUsedAt: string;
|
|
9
|
+
createdAt: string;
|
|
10
|
+
profileIds: string[];
|
|
11
|
+
}
|
|
12
|
+
export interface CommandHistoryStore {
|
|
13
|
+
version: number;
|
|
14
|
+
scope: 'global' | 'profile' | 'both';
|
|
15
|
+
maxEntries: number;
|
|
16
|
+
autoShow: boolean;
|
|
17
|
+
minChars: number;
|
|
18
|
+
hotkey: string;
|
|
19
|
+
entries: CommandHistoryEntry[];
|
|
20
|
+
}
|
|
21
|
+
export interface SuggestionResult {
|
|
22
|
+
entry: CommandHistoryEntry;
|
|
23
|
+
score: number;
|
|
24
|
+
highlights: number[];
|
|
25
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tabby-quick-snips",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Quick alias snippets plugin for Tabby Terminal",
|
|
5
|
+
"author": "Tamer",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/tamert/tabby-quick-snips.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/tamert/tabby-quick-snips#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/tamert/tabby-quick-snips/issues"
|
|
14
|
+
},
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"main": "dist/index.js",
|
|
19
|
+
"typings": "dist/index.d.ts",
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"README.md",
|
|
23
|
+
"LICENSE"
|
|
24
|
+
],
|
|
25
|
+
"keywords": [
|
|
26
|
+
"tabby",
|
|
27
|
+
"tabby-plugin",
|
|
28
|
+
"terminal",
|
|
29
|
+
"autocomplete",
|
|
30
|
+
"snippets",
|
|
31
|
+
"quick-commands"
|
|
32
|
+
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "webpack --mode production",
|
|
35
|
+
"watch": "webpack --mode development --watch"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"@angular/common": "^15.2.10",
|
|
39
|
+
"@angular/core": "^15.2.10",
|
|
40
|
+
"tabby-core": "^1.0.163",
|
|
41
|
+
"tabby-settings": "^1.0.163",
|
|
42
|
+
"tabby-terminal": "^1.0.163"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@angular/common": "^15.2.10",
|
|
46
|
+
"@angular/core": "^15.2.10",
|
|
47
|
+
"@types/node": "^18.19.130",
|
|
48
|
+
"tabby-core": "^1.0.163",
|
|
49
|
+
"tabby-settings": "^1.0.163",
|
|
50
|
+
"tabby-terminal": "^1.0.163",
|
|
51
|
+
"ts-loader": "^9.5.1",
|
|
52
|
+
"typescript": "^5.4.5",
|
|
53
|
+
"webpack": "^5.91.0",
|
|
54
|
+
"webpack-cli": "^5.1.4"
|
|
55
|
+
}
|
|
56
|
+
}
|