@openadapter/koda-tui 1.0.0-beta.3
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/README.md +791 -0
- package/dist/autocomplete.d.ts +53 -0
- package/dist/autocomplete.js +2 -0
- package/dist/components/box.d.ts +21 -0
- package/dist/components/box.js +1 -0
- package/dist/components/cancellable-loader.d.ts +21 -0
- package/dist/components/cancellable-loader.js +1 -0
- package/dist/components/editor.d.ts +249 -0
- package/dist/components/editor.js +17 -0
- package/dist/components/image.d.ts +27 -0
- package/dist/components/image.js +1 -0
- package/dist/components/input.d.ts +36 -0
- package/dist/components/input.js +2 -0
- package/dist/components/loader.d.ts +30 -0
- package/dist/components/loader.js +1 -0
- package/dist/components/markdown.d.ts +95 -0
- package/dist/components/markdown.js +5 -0
- package/dist/components/select-list.d.ts +49 -0
- package/dist/components/select-list.js +1 -0
- package/dist/components/settings-list.d.ts +49 -0
- package/dist/components/settings-list.js +1 -0
- package/dist/components/spacer.d.ts +11 -0
- package/dist/components/spacer.js +1 -0
- package/dist/components/text.d.ts +18 -0
- package/dist/components/text.js +1 -0
- package/dist/components/truncated-text.d.ts +12 -0
- package/dist/components/truncated-text.js +2 -0
- package/dist/editor-component.d.ts +38 -0
- package/dist/editor-component.js +0 -0
- package/dist/fuzzy.d.ts +15 -0
- package/dist/fuzzy.js +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +1 -0
- package/dist/keybindings.d.ts +192 -0
- package/dist/keybindings.js +1 -0
- package/dist/keys.d.ts +183 -0
- package/dist/keys.js +5 -0
- package/dist/kill-ring.d.ts +27 -0
- package/dist/kill-ring.js +1 -0
- package/dist/native-modifiers.d.ts +2 -0
- package/dist/native-modifiers.js +1 -0
- package/dist/stdin-buffer.d.ts +49 -0
- package/dist/stdin-buffer.js +1 -0
- package/dist/terminal-image.d.ts +89 -0
- package/dist/terminal-image.js +1 -0
- package/dist/terminal.d.ts +112 -0
- package/dist/terminal.js +1 -0
- package/dist/tui.d.ts +241 -0
- package/dist/tui.js +11 -0
- package/dist/undo-stack.d.ts +16 -0
- package/dist/undo-stack.js +1 -0
- package/dist/utils.d.ts +83 -0
- package/dist/utils.js +2 -0
- package/dist/word-navigation.d.ts +24 -0
- package/dist/word-navigation.js +1 -0
- package/native/darwin/prebuilds/darwin-arm64/darwin-modifiers.node +0 -0
- package/native/darwin/prebuilds/darwin-x64/darwin-modifiers.node +0 -0
- package/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
- package/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
- package/package.json +55 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { Component } from "../tui.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Default text styling for markdown content.
|
|
4
|
+
* Applied to all text unless overridden by markdown formatting.
|
|
5
|
+
*/
|
|
6
|
+
export interface DefaultTextStyle {
|
|
7
|
+
/** Foreground color function */
|
|
8
|
+
color?: (text: string) => string;
|
|
9
|
+
/** Background color function */
|
|
10
|
+
bgColor?: (text: string) => string;
|
|
11
|
+
/** Bold text */
|
|
12
|
+
bold?: boolean;
|
|
13
|
+
/** Italic text */
|
|
14
|
+
italic?: boolean;
|
|
15
|
+
/** Strikethrough text */
|
|
16
|
+
strikethrough?: boolean;
|
|
17
|
+
/** Underline text */
|
|
18
|
+
underline?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Theme functions for markdown elements.
|
|
22
|
+
* Each function takes text and returns styled text with ANSI codes.
|
|
23
|
+
*/
|
|
24
|
+
export interface MarkdownTheme {
|
|
25
|
+
heading: (text: string) => string;
|
|
26
|
+
link: (text: string) => string;
|
|
27
|
+
linkUrl: (text: string) => string;
|
|
28
|
+
code: (text: string) => string;
|
|
29
|
+
codeBlock: (text: string) => string;
|
|
30
|
+
codeBlockBorder: (text: string) => string;
|
|
31
|
+
quote: (text: string) => string;
|
|
32
|
+
quoteBorder: (text: string) => string;
|
|
33
|
+
hr: (text: string) => string;
|
|
34
|
+
listBullet: (text: string) => string;
|
|
35
|
+
bold: (text: string) => string;
|
|
36
|
+
italic: (text: string) => string;
|
|
37
|
+
strikethrough: (text: string) => string;
|
|
38
|
+
underline: (text: string) => string;
|
|
39
|
+
highlightCode?: (code: string, lang?: string) => string[];
|
|
40
|
+
/** Prefix applied to each rendered code block line (default: " ") */
|
|
41
|
+
codeBlockIndent?: string;
|
|
42
|
+
}
|
|
43
|
+
export interface MarkdownOptions {
|
|
44
|
+
/** Preserve source ordered-list markers instead of normalizing them from the list start. */
|
|
45
|
+
preserveOrderedListMarkers?: boolean;
|
|
46
|
+
}
|
|
47
|
+
export declare class Markdown implements Component {
|
|
48
|
+
private text;
|
|
49
|
+
private paddingX;
|
|
50
|
+
private paddingY;
|
|
51
|
+
private defaultTextStyle?;
|
|
52
|
+
private theme;
|
|
53
|
+
private options;
|
|
54
|
+
private defaultStylePrefix?;
|
|
55
|
+
private cachedText?;
|
|
56
|
+
private cachedWidth?;
|
|
57
|
+
private cachedLines?;
|
|
58
|
+
constructor(text: string, paddingX: number, paddingY: number, theme: MarkdownTheme, defaultTextStyle?: DefaultTextStyle, options?: MarkdownOptions);
|
|
59
|
+
setText(text: string): void;
|
|
60
|
+
invalidate(): void;
|
|
61
|
+
render(width: number): string[];
|
|
62
|
+
/**
|
|
63
|
+
* Apply default text style to a string.
|
|
64
|
+
* This is the base styling applied to all text content.
|
|
65
|
+
* NOTE: Background color is NOT applied here - it's applied at the padding stage
|
|
66
|
+
* to ensure it extends to the full line width.
|
|
67
|
+
*/
|
|
68
|
+
private applyDefaultStyle;
|
|
69
|
+
private getDefaultStylePrefix;
|
|
70
|
+
private getStylePrefix;
|
|
71
|
+
private getDefaultInlineStyleContext;
|
|
72
|
+
private renderToken;
|
|
73
|
+
private renderInlineTokens;
|
|
74
|
+
private getOrderedListMarker;
|
|
75
|
+
/**
|
|
76
|
+
* Render a list with proper nesting support
|
|
77
|
+
*/
|
|
78
|
+
private renderList;
|
|
79
|
+
/**
|
|
80
|
+
* Get the visible width of the longest word in a string.
|
|
81
|
+
*/
|
|
82
|
+
private getLongestWordWidth;
|
|
83
|
+
/**
|
|
84
|
+
* Wrap a table cell to fit into a column.
|
|
85
|
+
*
|
|
86
|
+
* Delegates to wrapTextWithAnsi() so ANSI codes + long tokens are handled
|
|
87
|
+
* consistently with the rest of the renderer.
|
|
88
|
+
*/
|
|
89
|
+
private wrapCellText;
|
|
90
|
+
/**
|
|
91
|
+
* Render a table with width-aware cell wrapping.
|
|
92
|
+
* Cells that don't fit are wrapped to multiple lines.
|
|
93
|
+
*/
|
|
94
|
+
private renderTable;
|
|
95
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
var X=Object.defineProperty;var T=($,e)=>X($,"name",{value:e,configurable:!0});import{Marked as R,Tokenizer as z}from"marked";import{getCapabilities as F,hyperlink as N,isImageLine as D}from"../terminal-image.js";import{applyBackgroundToLine as O,visibleWidth as M,wrapTextWithAnsi as C}from"../utils.js";const A=/^(~~)(?=[^\s~])((?:\\.|[^\\])*?(?:\\.|[^\s~\\]))\1(?=[^~]|$)/;class E extends z{static{T(this,"StrictStrikethroughTokenizer")}del(e){const t=A.exec(e);if(!t)return;const s=t[2];return{type:"del",raw:t[0],text:s,tokens:this.lexer.inlineTokens(s)}}}const j=new R;j.setOptions({tokenizer:new E});class Y{static{T(this,"Markdown")}text;paddingX;paddingY;defaultTextStyle;theme;options;defaultStylePrefix;cachedText;cachedWidth;cachedLines;constructor(e,t,s,h,r,i){this.text=e,this.paddingX=t,this.paddingY=s,this.theme=h,this.defaultTextStyle=r,this.options=i?{...i}:{}}setText(e){this.text=e,this.invalidate()}invalidate(){this.cachedText=void 0,this.cachedWidth=void 0,this.cachedLines=void 0}render(e){if(this.cachedLines&&this.cachedText===this.text&&this.cachedWidth===e)return this.cachedLines;const t=Math.max(1,e-this.paddingX*2);if(!this.text||this.text.trim()===""){const c=[];return this.cachedText=this.text,this.cachedWidth=e,this.cachedLines=c,c}const s=this.text.replace(/\t/g," "),h=j.lexer(s),r=[];for(let c=0;c<h.length;c++){const a=h[c],L=h[c+1],S=this.renderToken(a,t,L?.type);for(const W of S)r.push(W)}const i=[];for(const c of r)if(D(c))i.push(c);else for(const a of C(c,t))i.push(a);const g=" ".repeat(this.paddingX),n=" ".repeat(this.paddingX),f=this.defaultTextStyle?.bgColor,u=[];for(const c of i){if(D(c)){u.push(c);continue}const a=g+c+n;if(f)u.push(O(a,e,f));else{const L=M(a),S=Math.max(0,e-L);u.push(a+" ".repeat(S))}}const k=" ".repeat(e),p=[];for(let c=0;c<this.paddingY;c++){const a=f?O(k,e,f):k;p.push(a)}const m=p.concat(u,p);return this.cachedText=this.text,this.cachedWidth=e,this.cachedLines=m,m.length>0?m:[""]}applyDefaultStyle(e){if(!this.defaultTextStyle)return e;let t=e;return this.defaultTextStyle.color&&(t=this.defaultTextStyle.color(t)),this.defaultTextStyle.bold&&(t=this.theme.bold(t)),this.defaultTextStyle.italic&&(t=this.theme.italic(t)),this.defaultTextStyle.strikethrough&&(t=this.theme.strikethrough(t)),this.defaultTextStyle.underline&&(t=this.theme.underline(t)),t}getDefaultStylePrefix(){if(!this.defaultTextStyle)return"";if(this.defaultStylePrefix!==void 0)return this.defaultStylePrefix;const e="\0";let t=e;this.defaultTextStyle.color&&(t=this.defaultTextStyle.color(t)),this.defaultTextStyle.bold&&(t=this.theme.bold(t)),this.defaultTextStyle.italic&&(t=this.theme.italic(t)),this.defaultTextStyle.strikethrough&&(t=this.theme.strikethrough(t)),this.defaultTextStyle.underline&&(t=this.theme.underline(t));const s=t.indexOf(e);return this.defaultStylePrefix=s>=0?t.slice(0,s):"",this.defaultStylePrefix}getStylePrefix(e){const s=e("\0"),h=s.indexOf("\0");return h>=0?s.slice(0,h):""}getDefaultInlineStyleContext(){return{applyText:T(e=>this.applyDefaultStyle(e),"applyText"),stylePrefix:this.getDefaultStylePrefix()}}renderToken(e,t,s,h){const r=[];switch(e.type){case"heading":{const i=e.depth,g=`${"#".repeat(i)} `;let n;i===1?n=T(p=>this.theme.heading(this.theme.bold(this.theme.underline(p))),"headingStyleFn"):n=T(p=>this.theme.heading(this.theme.bold(p)),"headingStyleFn");const f={applyText:n,stylePrefix:this.getStylePrefix(n)},u=this.renderInlineTokens(e.tokens||[],f),k=i>=3?n(g)+u:u;r.push(k),s&&s!=="space"&&r.push("");break}case"paragraph":{const i=this.renderInlineTokens(e.tokens||[],h);r.push(i),s&&s!=="list"&&s!=="space"&&r.push("");break}case"text":r.push(this.renderInlineTokens([e],h));break;case"code":{const i=this.theme.codeBlockIndent??" ";if(r.push(this.theme.codeBlockBorder(`\`\`\`${e.lang||""}`)),this.theme.highlightCode){const g=this.theme.highlightCode(e.text,e.lang);for(const n of g)r.push(`${i}${n}`)}else{const g=e.text.split(`
|
|
2
|
+
`);for(const n of g)r.push(`${i}${this.theme.codeBlock(n)}`)}r.push(this.theme.codeBlockBorder("```")),s&&s!=="space"&&r.push("");break}case"list":{const i=this.renderList(e,0,t,h);r.push(...i);break}case"table":{const i=this.renderTable(e,t,s,h);r.push(...i);break}case"blockquote":{const i=T(m=>this.theme.quote(this.theme.italic(m)),"quoteStyle"),g=this.getStylePrefix(i),n=T(m=>{if(!g)return i(m);const c=m.replace(/\x1b\[0m/g,`\x1B[0m${g}`);return i(c)},"applyQuoteStyle"),f=Math.max(1,t-2),u={applyText:T(m=>m,"applyText"),stylePrefix:g},k=e.tokens||[],p=[];for(let m=0;m<k.length;m++){const c=k[m],a=k[m+1];p.push(...this.renderToken(c,f,a?.type,u))}for(;p.length>0&&p[p.length-1]==="";)p.pop();for(const m of p){const c=n(m),a=C(c,f);for(const L of a)r.push(this.theme.quoteBorder("\u2502 ")+L)}s&&s!=="space"&&r.push("");break}case"hr":r.push(this.theme.hr("\u2500".repeat(Math.min(t,80)))),s&&s!=="space"&&r.push("");break;case"html":"raw"in e&&typeof e.raw=="string"&&r.push(this.applyDefaultStyle(e.raw.trim()));break;case"space":r.push("");break;default:"text"in e&&typeof e.text=="string"&&r.push(e.text)}return r}renderInlineTokens(e,t){let s="";const h=t??this.getDefaultInlineStyleContext(),{applyText:r,stylePrefix:i}=h,g=T(n=>n.split(`
|
|
3
|
+
`).map(u=>r(u)).join(`
|
|
4
|
+
`),"applyTextWithNewlines");for(const n of e)switch(n.type){case"text":n.tokens&&n.tokens.length>0?s+=this.renderInlineTokens(n.tokens,h):s+=g(n.text);break;case"paragraph":s+=this.renderInlineTokens(n.tokens||[],h);break;case"strong":{const f=this.renderInlineTokens(n.tokens||[],h);s+=this.theme.bold(f)+i;break}case"em":{const f=this.renderInlineTokens(n.tokens||[],h);s+=this.theme.italic(f)+i;break}case"codespan":s+=this.theme.code(n.text)+i;break;case"link":{const f=this.renderInlineTokens(n.tokens||[],h),u=this.theme.link(this.theme.underline(f));if(F().hyperlinks)s+=N(u,n.href)+i;else{const k=n.href.startsWith("mailto:")?n.href.slice(7):n.href;n.text===n.href||n.text===k?s+=u+i:s+=u+this.theme.linkUrl(` (${n.href})`)+i}break}case"br":s+=`
|
|
5
|
+
`;break;case"del":{const f=this.renderInlineTokens(n.tokens||[],h);s+=this.theme.strikethrough(f)+i;break}case"html":"raw"in n&&typeof n.raw=="string"&&(s+=g(n.raw));break;default:"text"in n&&typeof n.text=="string"&&(s+=g(n.text))}for(;i&&s.endsWith(i);)s=s.slice(0,-i.length);return s}getOrderedListMarker(e){const t=/^(?: {0,3})(\d{1,9}[.)])[ \t]+/.exec(e.raw);return t?`${t[1]} `:void 0}renderList(e,t,s,h){const r=[],i=" ".repeat(t),g=typeof e.start=="number"?e.start:1;for(let n=0;n<e.items.length;n++){const f=e.items[n],u=e.ordered?this.options.preserveOrderedListMarkers?this.getOrderedListMarker(f)??`${g+n}. `:`${g+n}. `:"- ",k=f.task?`[${f.checked?"x":" "}] `:"",p=u+k,m=i+this.theme.listBullet(p),c=i+" ".repeat(M(p)),a=Math.max(1,s-M(m));let L=!1;for(const S of f.tokens){if(S.type==="list"){r.push(...this.renderList(S,t+1,s,h)),L=!0;continue}const W=this.renderToken(S,a,void 0,h);for(const v of W)for(const P of C(v,a)){const B=L?c:m;r.push(B+P),L=!0}}L||r.push(m)}return r}getLongestWordWidth(e,t){const s=e.split(/\s+/).filter(r=>r.length>0);let h=0;for(const r of s)h=Math.max(h,M(r));return t===void 0?h:Math.min(h,t)}wrapCellText(e,t){return C(e,Math.max(1,t))}renderTable(e,t,s,h){const r=[],i=e.header.length;if(i===0)return r;const g=3*i+1,n=t-g;if(n<i){const o=e.raw?C(e.raw,t):[];return s&&s!=="space"&&o.push(""),o}const f=30,u=[],k=[];for(let o=0;o<i;o++){const d=this.renderInlineTokens(e.header[o].tokens||[],h);u[o]=M(d),k[o]=Math.max(1,this.getLongestWordWidth(d,f))}for(const o of e.rows)for(let d=0;d<o.length;d++){const y=this.renderInlineTokens(o[d].tokens||[],h);u[d]=Math.max(u[d]||0,M(y)),k[d]=Math.max(k[d]||1,this.getLongestWordWidth(y,f))}let p=k,m=p.reduce((o,d)=>o+d,0);if(m>n){p=new Array(i).fill(1);const o=n-i;if(o>0){const d=k.reduce((l,b)=>l+Math.max(0,b-1),0),y=k.map(l=>{const b=Math.max(0,l-1);return d>0?Math.floor(b/d*o):0});for(let l=0;l<i;l++)p[l]+=y[l]??0;const w=y.reduce((l,b)=>l+b,0);let x=o-w;for(let l=0;x>0&&l<i;l++)p[l]++,x--}m=p.reduce((d,y)=>d+y,0)}const c=u.reduce((o,d)=>o+d,0)+g;let a;if(c<=t)a=u.map((o,d)=>Math.max(o,p[d]));else{const o=u.reduce((x,l,b)=>x+Math.max(0,l-p[b]),0),d=Math.max(0,n-m);a=p.map((x,l)=>{const b=u[l],q=Math.max(0,b-x);let I=0;return o>0&&(I=Math.floor(q/o*d)),x+I});const y=a.reduce((x,l)=>x+l,0);let w=n-y;for(;w>0;){let x=!1;for(let l=0;l<i&&w>0;l++)a[l]<u[l]&&(a[l]++,w--,x=!0);if(!x)break}}const L=a.map(o=>"\u2500".repeat(o));r.push(`\u250C\u2500${L.join("\u2500\u252C\u2500")}\u2500\u2510`);const S=e.header.map((o,d)=>{const y=this.renderInlineTokens(o.tokens||[],h);return this.wrapCellText(y,a[d])}),W=Math.max(...S.map(o=>o.length));for(let o=0;o<W;o++){const d=S.map((y,w)=>{const x=y[o]||"",l=x+" ".repeat(Math.max(0,a[w]-M(x)));return this.theme.bold(l)});r.push(`\u2502 ${d.join(" \u2502 ")} \u2502`)}const P=`\u251C\u2500${a.map(o=>"\u2500".repeat(o)).join("\u2500\u253C\u2500")}\u2500\u2524`;r.push(P);for(let o=0;o<e.rows.length;o++){const y=e.rows[o].map((x,l)=>{const b=this.renderInlineTokens(x.tokens||[],h);return this.wrapCellText(b,a[l])}),w=Math.max(...y.map(x=>x.length));for(let x=0;x<w;x++){const l=y.map((b,q)=>{const I=b[x]||"";return I+" ".repeat(Math.max(0,a[q]-M(I)))});r.push(`\u2502 ${l.join(" \u2502 ")} \u2502`)}o<e.rows.length-1&&r.push(P)}const B=a.map(o=>"\u2500".repeat(o));return r.push(`\u2514\u2500${B.join("\u2500\u2534\u2500")}\u2500\u2518`),s&&s!=="space"&&r.push(""),r}}export{Y as Markdown};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Component } from "../tui.ts";
|
|
2
|
+
export interface SelectItem {
|
|
3
|
+
value: string;
|
|
4
|
+
label: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface SelectListTheme {
|
|
8
|
+
selectedPrefix: (text: string) => string;
|
|
9
|
+
selectedText: (text: string) => string;
|
|
10
|
+
description: (text: string) => string;
|
|
11
|
+
scrollInfo: (text: string) => string;
|
|
12
|
+
noMatch: (text: string) => string;
|
|
13
|
+
}
|
|
14
|
+
export interface SelectListTruncatePrimaryContext {
|
|
15
|
+
text: string;
|
|
16
|
+
maxWidth: number;
|
|
17
|
+
columnWidth: number;
|
|
18
|
+
item: SelectItem;
|
|
19
|
+
isSelected: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface SelectListLayoutOptions {
|
|
22
|
+
minPrimaryColumnWidth?: number;
|
|
23
|
+
maxPrimaryColumnWidth?: number;
|
|
24
|
+
truncatePrimary?: (context: SelectListTruncatePrimaryContext) => string;
|
|
25
|
+
}
|
|
26
|
+
export declare class SelectList implements Component {
|
|
27
|
+
private items;
|
|
28
|
+
private filteredItems;
|
|
29
|
+
private selectedIndex;
|
|
30
|
+
private maxVisible;
|
|
31
|
+
private theme;
|
|
32
|
+
private layout;
|
|
33
|
+
onSelect?: (item: SelectItem) => void;
|
|
34
|
+
onCancel?: () => void;
|
|
35
|
+
onSelectionChange?: (item: SelectItem) => void;
|
|
36
|
+
constructor(items: SelectItem[], maxVisible: number, theme: SelectListTheme, layout?: SelectListLayoutOptions);
|
|
37
|
+
setFilter(filter: string): void;
|
|
38
|
+
setSelectedIndex(index: number): void;
|
|
39
|
+
invalidate(): void;
|
|
40
|
+
render(width: number): string[];
|
|
41
|
+
handleInput(keyData: string): void;
|
|
42
|
+
private renderItem;
|
|
43
|
+
private getPrimaryColumnWidth;
|
|
44
|
+
private getPrimaryColumnBounds;
|
|
45
|
+
private truncatePrimary;
|
|
46
|
+
private getDisplayValue;
|
|
47
|
+
private notifySelectionChange;
|
|
48
|
+
getSelectedItem(): SelectItem | null;
|
|
49
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var V=Object.defineProperty;var o=(l,t)=>V(l,"name",{value:t,configurable:!0});import{getKeybindings as S}from"../keybindings.js";import{truncateToWidth as m,visibleWidth as x}from"../utils.js";const M=32,C=2,T=10,b=o(l=>l.replace(/[\r\n]+/g," ").trim(),"normalizeToSingleLine"),$=o((l,t,e)=>Math.max(t,Math.min(l,e)),"clamp");class D{static{o(this,"SelectList")}items=[];filteredItems=[];selectedIndex=0;maxVisible=5;theme;layout;onSelect;onCancel;onSelectionChange;constructor(t,e,i,n={}){this.items=t,this.filteredItems=t,this.maxVisible=e,this.theme=i,this.layout=n}setFilter(t){this.filteredItems=this.items.filter(e=>e.value.toLowerCase().startsWith(t.toLowerCase())),this.selectedIndex=0}setSelectedIndex(t){this.selectedIndex=Math.max(0,Math.min(t,this.filteredItems.length-1))}invalidate(){}render(t){const e=[];if(this.filteredItems.length===0)return e.push(this.theme.noMatch(" No matching commands")),e;const i=this.getPrimaryColumnWidth(),n=Math.max(0,Math.min(this.selectedIndex-Math.floor(this.maxVisible/2),this.filteredItems.length-this.maxVisible)),r=Math.min(n+this.maxVisible,this.filteredItems.length);for(let s=n;s<r;s++){const h=this.filteredItems[s];if(!h)continue;const a=s===this.selectedIndex,c=h.description?b(h.description):void 0;e.push(this.renderItem(h,a,t,c,i))}if(n>0||r<this.filteredItems.length){const s=` (${this.selectedIndex+1}/${this.filteredItems.length})`;e.push(this.theme.scrollInfo(m(s,t-2,"")))}return e}handleInput(t){const e=S();if(e.matches(t,"tui.select.up"))this.selectedIndex=this.selectedIndex===0?this.filteredItems.length-1:this.selectedIndex-1,this.notifySelectionChange();else if(e.matches(t,"tui.select.down"))this.selectedIndex=this.selectedIndex===this.filteredItems.length-1?0:this.selectedIndex+1,this.notifySelectionChange();else if(e.matches(t,"tui.select.confirm")){const i=this.filteredItems[this.selectedIndex];i&&this.onSelect&&this.onSelect(i)}else e.matches(t,"tui.select.cancel")&&this.onCancel&&this.onCancel()}renderItem(t,e,i,n,r){const s=e?"\u2192 ":" ",h=x(s);if(n&&i>40){const d=Math.max(1,Math.min(r,i-h-4)),p=Math.max(1,d-C),u=this.truncatePrimary(t,e,p,d),f=x(u),I=" ".repeat(Math.max(1,d-f)),P=h+f+I.length,g=i-P-2;if(g>T){const y=m(n,g,"");if(e)return this.theme.selectedText(`${s}${u}${I}${y}`);const W=this.theme.description(I+y);return s+u+W}}const a=i-h-2,c=this.truncatePrimary(t,e,a,a);return e?this.theme.selectedText(`${s}${c}`):s+c}getPrimaryColumnWidth(){const{min:t,max:e}=this.getPrimaryColumnBounds(),i=this.filteredItems.reduce((n,r)=>Math.max(n,x(this.getDisplayValue(r))+C),0);return $(i,t,e)}getPrimaryColumnBounds(){const t=this.layout.minPrimaryColumnWidth??this.layout.maxPrimaryColumnWidth??M,e=this.layout.maxPrimaryColumnWidth??this.layout.minPrimaryColumnWidth??M;return{min:Math.max(1,Math.min(t,e)),max:Math.max(1,Math.max(t,e))}}truncatePrimary(t,e,i,n){const r=this.getDisplayValue(t),s=this.layout.truncatePrimary?this.layout.truncatePrimary({text:r,maxWidth:i,columnWidth:n,item:t,isSelected:e}):m(r,i,"");return m(s,i,"")}getDisplayValue(t){return t.label||t.value}notifySelectionChange(){const t=this.filteredItems[this.selectedIndex];t&&this.onSelectionChange&&this.onSelectionChange(t)}getSelectedItem(){return this.filteredItems[this.selectedIndex]||null}}export{D as SelectList};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Component } from "../tui.ts";
|
|
2
|
+
export interface SettingItem {
|
|
3
|
+
/** Unique identifier for this setting */
|
|
4
|
+
id: string;
|
|
5
|
+
/** Display label (left side) */
|
|
6
|
+
label: string;
|
|
7
|
+
/** Optional description shown when selected */
|
|
8
|
+
description?: string;
|
|
9
|
+
/** Current value to display (right side) */
|
|
10
|
+
currentValue: string;
|
|
11
|
+
/** If provided, Enter/Space cycles through these values */
|
|
12
|
+
values?: string[];
|
|
13
|
+
/** If provided, Enter opens this submenu. Receives current value and done callback. */
|
|
14
|
+
submenu?: (currentValue: string, done: (selectedValue?: string) => void) => Component;
|
|
15
|
+
}
|
|
16
|
+
export interface SettingsListTheme {
|
|
17
|
+
label: (text: string, selected: boolean) => string;
|
|
18
|
+
value: (text: string, selected: boolean) => string;
|
|
19
|
+
description: (text: string) => string;
|
|
20
|
+
cursor: string;
|
|
21
|
+
hint: (text: string) => string;
|
|
22
|
+
}
|
|
23
|
+
export interface SettingsListOptions {
|
|
24
|
+
enableSearch?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare class SettingsList implements Component {
|
|
27
|
+
private items;
|
|
28
|
+
private filteredItems;
|
|
29
|
+
private theme;
|
|
30
|
+
private selectedIndex;
|
|
31
|
+
private maxVisible;
|
|
32
|
+
private onChange;
|
|
33
|
+
private onCancel;
|
|
34
|
+
private searchInput?;
|
|
35
|
+
private searchEnabled;
|
|
36
|
+
private submenuComponent;
|
|
37
|
+
private submenuItemIndex;
|
|
38
|
+
constructor(items: SettingItem[], maxVisible: number, theme: SettingsListTheme, onChange: (id: string, newValue: string) => void, onCancel: () => void, options?: SettingsListOptions);
|
|
39
|
+
/** Update an item's currentValue */
|
|
40
|
+
updateValue(id: string, newValue: string): void;
|
|
41
|
+
invalidate(): void;
|
|
42
|
+
render(width: number): string[];
|
|
43
|
+
private renderMainList;
|
|
44
|
+
handleInput(data: string): void;
|
|
45
|
+
private activateItem;
|
|
46
|
+
private closeSubmenu;
|
|
47
|
+
private applyFilter;
|
|
48
|
+
private addHintLine;
|
|
49
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var E=Object.defineProperty;var I=(d,e)=>E(d,"name",{value:e,configurable:!0});import{fuzzyFilter as V}from"../fuzzy.js";import{getKeybindings as M}from"../keybindings.js";import{truncateToWidth as l,visibleWidth as r,wrapTextWithAnsi as L}from"../utils.js";import{Input as y}from"./input.js";class F{static{I(this,"SettingsList")}items;filteredItems;theme;selectedIndex=0;maxVisible;onChange;onCancel;searchInput;searchEnabled;submenuComponent=null;submenuItemIndex=null;constructor(e,t,s,n,a,c={}){this.items=e,this.filteredItems=e,this.maxVisible=t,this.theme=s,this.onChange=n,this.onCancel=a,this.searchEnabled=c.enableSearch??!1,this.searchEnabled&&(this.searchInput=new y)}updateValue(e,t){const s=this.items.find(n=>n.id===e);s&&(s.currentValue=t)}invalidate(){this.submenuComponent?.invalidate?.()}render(e){return this.submenuComponent?this.submenuComponent.render(e):this.renderMainList(e)}renderMainList(e){const t=[];if(this.searchEnabled&&this.searchInput&&(t.push(...this.searchInput.render(e)),t.push("")),this.items.length===0)return t.push(this.theme.hint(" No settings available")),this.searchEnabled&&this.addHintLine(t,e),t;const s=this.searchEnabled?this.filteredItems:this.items;if(s.length===0)return t.push(l(this.theme.hint(" No matching settings"),e)),this.addHintLine(t,e),t;const n=Math.max(0,Math.min(this.selectedIndex-Math.floor(this.maxVisible/2),s.length-this.maxVisible)),a=Math.min(n+this.maxVisible,s.length),c=Math.min(30,Math.max(...this.items.map(i=>r(i.label))));for(let i=n;i<a;i++){const h=s[i];if(!h)continue;const u=i===this.selectedIndex,o=u?this.theme.cursor:" ",f=r(o),b=h.label+" ".repeat(Math.max(0,c-r(h.label))),x=this.theme.label(b,u),p=" ",g=f+c+r(p),C=e-g-2,v=this.theme.value(l(h.currentValue,C,""),u);t.push(l(o+x+p+v,e))}if(n>0||a<s.length){const i=` (${this.selectedIndex+1}/${s.length})`;t.push(this.theme.hint(l(i,e-2,"")))}const m=s[this.selectedIndex];if(m?.description){t.push("");const i=L(m.description,e-4);for(const h of i)t.push(this.theme.description(` ${h}`))}return this.addHintLine(t,e),t}handleInput(e){if(this.submenuComponent){this.submenuComponent.handleInput?.(e);return}const t=M(),s=this.searchEnabled?this.filteredItems:this.items;if(t.matches(e,"tui.select.up")){if(s.length===0)return;this.selectedIndex=this.selectedIndex===0?s.length-1:this.selectedIndex-1}else if(t.matches(e,"tui.select.down")){if(s.length===0)return;this.selectedIndex=this.selectedIndex===s.length-1?0:this.selectedIndex+1}else if(t.matches(e,"tui.select.confirm")||e===" ")this.activateItem();else if(t.matches(e,"tui.select.cancel"))this.onCancel();else if(this.searchEnabled&&this.searchInput){const n=e.replace(/ /g,"");if(!n)return;this.searchInput.handleInput(n),this.applyFilter(this.searchInput.getValue())}}activateItem(){const e=this.searchEnabled?this.filteredItems[this.selectedIndex]:this.items[this.selectedIndex];if(e){if(e.submenu)this.submenuItemIndex=this.selectedIndex,this.submenuComponent=e.submenu(e.currentValue,t=>{t!==void 0&&(e.currentValue=t,this.onChange(e.id,t)),this.closeSubmenu()});else if(e.values&&e.values.length>0){const s=(e.values.indexOf(e.currentValue)+1)%e.values.length,n=e.values[s];e.currentValue=n,this.onChange(e.id,n)}}}closeSubmenu(){this.submenuComponent=null,this.submenuItemIndex!==null&&(this.selectedIndex=this.submenuItemIndex,this.submenuItemIndex=null)}applyFilter(e){this.filteredItems=V(this.items,e,t=>t.label),this.selectedIndex=0}addHintLine(e,t){e.push(""),e.push(l(this.theme.hint(this.searchEnabled?" Type to search \xB7 Enter/Space to change \xB7 Esc to cancel":" Enter/Space to change \xB7 Esc to cancel"),t))}}export{F as SettingsList};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Component } from "../tui.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Spacer component that renders empty lines
|
|
4
|
+
*/
|
|
5
|
+
export declare class Spacer implements Component {
|
|
6
|
+
private lines;
|
|
7
|
+
constructor(lines?: number);
|
|
8
|
+
setLines(lines: number): void;
|
|
9
|
+
invalidate(): void;
|
|
10
|
+
render(_width: number): string[];
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var r=Object.defineProperty;var n=(e,s)=>r(e,"name",{value:s,configurable:!0});class c{static{n(this,"Spacer")}lines;constructor(s=1){this.lines=s}setLines(s){this.lines=s}invalidate(){}render(s){const t=[];for(let i=0;i<this.lines;i++)t.push("");return t}}export{c as Spacer};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Component } from "../tui.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Text component - displays multi-line text with word wrapping
|
|
4
|
+
*/
|
|
5
|
+
export declare class Text implements Component {
|
|
6
|
+
private text;
|
|
7
|
+
private paddingX;
|
|
8
|
+
private paddingY;
|
|
9
|
+
private customBgFn?;
|
|
10
|
+
private cachedText?;
|
|
11
|
+
private cachedWidth?;
|
|
12
|
+
private cachedLines?;
|
|
13
|
+
constructor(text?: string, paddingX?: number, paddingY?: number, customBgFn?: (text: string) => string);
|
|
14
|
+
setText(text: string): void;
|
|
15
|
+
setCustomBgFn(customBgFn?: (text: string) => string): void;
|
|
16
|
+
invalidate(): void;
|
|
17
|
+
render(width: number): string[];
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var m=Object.defineProperty;var u=(o,t)=>m(o,"name",{value:t,configurable:!0});import{applyBackgroundToLine as p,visibleWidth as L,wrapTextWithAnsi as T}from"../utils.js";class F{static{u(this,"Text")}text;paddingX;paddingY;customBgFn;cachedText;cachedWidth;cachedLines;constructor(t="",s=1,n=1,c){this.text=t,this.paddingX=s,this.paddingY=n,this.customBgFn=c}setText(t){this.text=t,this.cachedText=void 0,this.cachedWidth=void 0,this.cachedLines=void 0}setCustomBgFn(t){this.customBgFn=t,this.cachedText=void 0,this.cachedWidth=void 0,this.cachedLines=void 0}invalidate(){this.cachedText=void 0,this.cachedWidth=void 0,this.cachedLines=void 0}render(t){if(this.cachedLines&&this.cachedText===this.text&&this.cachedWidth===t)return this.cachedLines;if(!this.text||this.text.trim()===""){const e=[];return this.cachedText=this.text,this.cachedWidth=t,this.cachedLines=e,e}const s=this.text.replace(/\t/g," "),n=Math.max(1,t-this.paddingX*2),c=T(s,n),g=" ".repeat(this.paddingX),x=" ".repeat(this.paddingX),h=[];for(const e of c){const i=g+e+x;if(this.customBgFn)h.push(p(i,t,this.customBgFn));else{const f=L(i),l=Math.max(0,t-f);h.push(i+" ".repeat(l))}}const r=" ".repeat(t),d=[];for(let e=0;e<this.paddingY;e++){const i=this.customBgFn?p(r,t,this.customBgFn):r;d.push(i)}const a=[...d,...h,...d];return this.cachedText=this.text,this.cachedWidth=t,this.cachedLines=a,a.length>0?a:[""]}}export{F as Text};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Component } from "../tui.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Text component that truncates to fit viewport width
|
|
4
|
+
*/
|
|
5
|
+
export declare class TruncatedText implements Component {
|
|
6
|
+
private text;
|
|
7
|
+
private paddingX;
|
|
8
|
+
private paddingY;
|
|
9
|
+
constructor(text: string, paddingX?: number, paddingY?: number);
|
|
10
|
+
invalidate(): void;
|
|
11
|
+
render(width: number): string[];
|
|
12
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var f=Object.defineProperty;var h=(d,t)=>f(d,"name",{value:t,configurable:!0});import{truncateToWidth as m,visibleWidth as T}from"../utils.js";class b{static{h(this,"TruncatedText")}text;paddingX;paddingY;constructor(t,i=0,n=0){this.text=t,this.paddingX=i,this.paddingY=n}invalidate(){}render(t){const i=[],n=" ".repeat(t);for(let e=0;e<this.paddingY;e++)i.push(n);const r=Math.max(1,t-this.paddingX*2);let s=this.text;const a=this.text.indexOf(`
|
|
2
|
+
`);a!==-1&&(s=this.text.substring(0,a));const o=m(s,r),l=" ".repeat(this.paddingX),c=" ".repeat(this.paddingX),p=l+o+c,g=T(p),x=Math.max(0,t-g),u=p+" ".repeat(x);i.push(u);for(let e=0;e<this.paddingY;e++)i.push(n);return i}}export{b as TruncatedText};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { AutocompleteProvider } from "./autocomplete.ts";
|
|
2
|
+
import type { Component } from "./tui.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Interface for custom editor components.
|
|
5
|
+
*
|
|
6
|
+
* This allows extensions to provide their own editor implementation
|
|
7
|
+
* (e.g., vim mode, emacs mode, custom keybindings) while maintaining
|
|
8
|
+
* compatibility with the core application.
|
|
9
|
+
*/
|
|
10
|
+
export interface EditorComponent extends Component {
|
|
11
|
+
/** Get the current text content */
|
|
12
|
+
getText(): string;
|
|
13
|
+
/** Set the text content */
|
|
14
|
+
setText(text: string): void;
|
|
15
|
+
/** Handle raw terminal input (key presses, paste sequences, etc.) */
|
|
16
|
+
handleInput(data: string): void;
|
|
17
|
+
/** Called when user submits (e.g., Enter key) */
|
|
18
|
+
onSubmit?: (text: string) => void;
|
|
19
|
+
/** Called when text changes */
|
|
20
|
+
onChange?: (text: string) => void;
|
|
21
|
+
/** Add text to history for up/down navigation */
|
|
22
|
+
addToHistory?(text: string): void;
|
|
23
|
+
/** Insert text at current cursor position */
|
|
24
|
+
insertTextAtCursor?(text: string): void;
|
|
25
|
+
/**
|
|
26
|
+
* Get text with any markers expanded (e.g., paste markers).
|
|
27
|
+
* Falls back to getText() if not implemented.
|
|
28
|
+
*/
|
|
29
|
+
getExpandedText?(): string;
|
|
30
|
+
/** Set the autocomplete provider */
|
|
31
|
+
setAutocompleteProvider?(provider: AutocompleteProvider): void;
|
|
32
|
+
/** Border color function */
|
|
33
|
+
borderColor?: (str: string) => string;
|
|
34
|
+
/** Set horizontal padding */
|
|
35
|
+
setPaddingX?(padding: number): void;
|
|
36
|
+
/** Set max visible items in autocomplete dropdown */
|
|
37
|
+
setAutocompleteMaxVisible?(maxVisible: number): void;
|
|
38
|
+
}
|
|
File without changes
|
package/dist/fuzzy.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fuzzy matching utilities.
|
|
3
|
+
* Matches if all query characters appear in order (not necessarily consecutive).
|
|
4
|
+
* Lower score = better match.
|
|
5
|
+
*/
|
|
6
|
+
export interface FuzzyMatch {
|
|
7
|
+
matches: boolean;
|
|
8
|
+
score: number;
|
|
9
|
+
}
|
|
10
|
+
export declare function fuzzyMatch(query: string, text: string): FuzzyMatch;
|
|
11
|
+
/**
|
|
12
|
+
* Filter and sort items by fuzzy match quality (best matches first).
|
|
13
|
+
* Supports space-separated tokens: all tokens must match.
|
|
14
|
+
*/
|
|
15
|
+
export declare function fuzzyFilter<T>(items: T[], query: string, getText: (item: T) => string): T[];
|
package/dist/fuzzy.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var x=Object.defineProperty;var m=(c,n)=>x(c,"name",{value:n,configurable:!0});function $(c,n){const l=c.toLowerCase(),r=n.toLowerCase(),a=m(e=>{if(e.length===0)return{matches:!0,score:0};if(e.length>r.length)return{matches:!1,score:0};let g=0,i=0,p=-1,M=0;for(let s=0;s<r.length&&g<e.length;s++)if(r[s]===e[g]){const w=s===0||/[\s\-_./:]/.test(r[s-1]);p===s-1?(M++,i-=M*5):(M=0,p>=0&&(i+=(s-p-1)*2)),w&&(i-=10),i+=s*.1,p=s,g++}return g<e.length?{matches:!1,score:0}:(e===r&&(i-=100),{matches:!0,score:i})},"matchQuery"),t=a(l);if(t.matches)return t;const o=l.match(/^(?<letters>[a-z]+)(?<digits>[0-9]+)$/),h=l.match(/^(?<digits>[0-9]+)(?<letters>[a-z]+)$/),f=o?`${o.groups?.digits??""}${o.groups?.letters??""}`:h?`${h.groups?.letters??""}${h.groups?.digits??""}`:"";if(!f)return t;const u=a(f);return u.matches?{matches:!0,score:u.score+5}:t}m($,"fuzzyMatch");function L(c,n,l){if(!n.trim())return c;const r=n.trim().split(/\s+/).filter(t=>t.length>0);if(r.length===0)return c;const a=[];for(const t of c){const o=l(t);let h=0,f=!0;for(const u of r){const e=$(u,o);if(e.matches)h+=e.score;else{f=!1;break}}f&&a.push({item:t,totalScore:h})}return a.sort((t,o)=>t.totalScore-o.totalScore),a.map(t=>t.item)}m(L,"fuzzyFilter");export{L as fuzzyFilter,$ as fuzzyMatch};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export { type AutocompleteItem, type AutocompleteProvider, type AutocompleteSuggestions, CombinedAutocompleteProvider, type SlashCommand, } from "./autocomplete.ts";
|
|
2
|
+
export { Box } from "./components/box.ts";
|
|
3
|
+
export { CancellableLoader } from "./components/cancellable-loader.ts";
|
|
4
|
+
export { Editor, type EditorOptions, type EditorTheme } from "./components/editor.ts";
|
|
5
|
+
export { Image, type ImageOptions, type ImageTheme } from "./components/image.ts";
|
|
6
|
+
export { Input } from "./components/input.ts";
|
|
7
|
+
export { Loader, type LoaderIndicatorOptions } from "./components/loader.ts";
|
|
8
|
+
export { type DefaultTextStyle, Markdown, type MarkdownOptions, type MarkdownTheme } from "./components/markdown.ts";
|
|
9
|
+
export { type SelectItem, SelectList, type SelectListLayoutOptions, type SelectListTheme, type SelectListTruncatePrimaryContext, } from "./components/select-list.ts";
|
|
10
|
+
export { type SettingItem, SettingsList, type SettingsListTheme } from "./components/settings-list.ts";
|
|
11
|
+
export { Spacer } from "./components/spacer.ts";
|
|
12
|
+
export { Text } from "./components/text.ts";
|
|
13
|
+
export { TruncatedText } from "./components/truncated-text.ts";
|
|
14
|
+
export type { EditorComponent } from "./editor-component.ts";
|
|
15
|
+
export { type FuzzyMatch, fuzzyFilter, fuzzyMatch } from "./fuzzy.ts";
|
|
16
|
+
export { getKeybindings, type Keybinding, type KeybindingConflict, type KeybindingDefinition, type KeybindingDefinitions, type Keybindings, type KeybindingsConfig, KeybindingsManager, setKeybindings, TUI_KEYBINDINGS, } from "./keybindings.ts";
|
|
17
|
+
export { decodeKittyPrintable, isKeyRelease, isKeyRepeat, isKittyProtocolActive, Key, type KeyEventType, type KeyId, matchesKey, parseKey, setKittyProtocolActive, } from "./keys.ts";
|
|
18
|
+
export { StdinBuffer, type StdinBufferEventMap, type StdinBufferOptions } from "./stdin-buffer.ts";
|
|
19
|
+
export { ProcessTerminal, type Terminal } from "./terminal.ts";
|
|
20
|
+
export { allocateImageId, type CellDimensions, calculateImageRows, deleteAllKittyImages, deleteKittyImage, detectCapabilities, encodeITerm2, encodeKitty, getCapabilities, getCellDimensions, getGifDimensions, getImageDimensions, getJpegDimensions, getPngDimensions, getWebpDimensions, hyperlink, type ImageDimensions, type ImageProtocol, type ImageRenderOptions, imageFallback, renderImage, resetCapabilitiesCache, setCapabilities, setCellDimensions, type TerminalCapabilities, } from "./terminal-image.ts";
|
|
21
|
+
export { type Component, Container, CURSOR_MARKER, type Focusable, isFocusable, type OverlayAnchor, type OverlayHandle, type OverlayMargin, type OverlayOptions, type OverlayUnfocusOptions, type SizeValue, TUI, } from "./tui.ts";
|
|
22
|
+
export { truncateToWidth, visibleWidth, wrapTextWithAnsi } from "./utils.ts";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{CombinedAutocompleteProvider as o}from"./autocomplete.js";import{Box as i}from"./components/box.js";import{CancellableLoader as s}from"./components/cancellable-loader.js";import{Editor as n}from"./components/editor.js";import{Image as l}from"./components/image.js";import{Input as x}from"./components/input.js";import{Loader as g}from"./components/loader.js";import{Markdown as y}from"./components/markdown.js";import{SelectList as b}from"./components/select-list.js";import{SettingsList as C}from"./components/settings-list.js";import{Spacer as T}from"./components/spacer.js";import{Text as h}from"./components/text.js";import{TruncatedText as A}from"./components/truncated-text.js";import{fuzzyFilter as S,fuzzyMatch as v}from"./fuzzy.js";import{getKeybindings as L,KeybindingsManager as M,setKeybindings as W,TUI_KEYBINDINGS as k}from"./keybindings.js";import{decodeKittyPrintable as B,isKeyRelease as E,isKeyRepeat as F,isKittyProtocolActive as U,Key as G,matchesKey as N,parseKey as _,setKittyProtocolActive as J}from"./keys.js";import{StdinBuffer as Y}from"./stdin-buffer.js";import{ProcessTerminal as q}from"./terminal.js";import{allocateImageId as Q,calculateImageRows as V,deleteAllKittyImages as X,deleteKittyImage as Z,detectCapabilities as $,encodeITerm2 as ee,encodeKitty as te,getCapabilities as oe,getCellDimensions as re,getGifDimensions as ie,getImageDimensions as ae,getJpegDimensions as se,getPngDimensions as me,getWebpDimensions as ne,hyperlink as pe,imageFallback as le,renderImage as fe,resetCapabilitiesCache as xe,setCapabilities as ce,setCellDimensions as ge}from"./terminal-image.js";import{Container as ye,CURSOR_MARKER as Ke,isFocusable as be,TUI as Ie}from"./tui.js";import{truncateToWidth as ue,visibleWidth as Te,wrapTextWithAnsi as De}from"./utils.js";export{i as Box,Ke as CURSOR_MARKER,s as CancellableLoader,o as CombinedAutocompleteProvider,ye as Container,n as Editor,l as Image,x as Input,G as Key,M as KeybindingsManager,g as Loader,y as Markdown,q as ProcessTerminal,b as SelectList,C as SettingsList,T as Spacer,Y as StdinBuffer,Ie as TUI,k as TUI_KEYBINDINGS,h as Text,A as TruncatedText,Q as allocateImageId,V as calculateImageRows,B as decodeKittyPrintable,X as deleteAllKittyImages,Z as deleteKittyImage,$ as detectCapabilities,ee as encodeITerm2,te as encodeKitty,S as fuzzyFilter,v as fuzzyMatch,oe as getCapabilities,re as getCellDimensions,ie as getGifDimensions,ae as getImageDimensions,se as getJpegDimensions,L as getKeybindings,me as getPngDimensions,ne as getWebpDimensions,pe as hyperlink,le as imageFallback,be as isFocusable,E as isKeyRelease,F as isKeyRepeat,U as isKittyProtocolActive,N as matchesKey,_ as parseKey,fe as renderImage,xe as resetCapabilitiesCache,ce as setCapabilities,ge as setCellDimensions,W as setKeybindings,J as setKittyProtocolActive,ue as truncateToWidth,Te as visibleWidth,De as wrapTextWithAnsi};
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { type KeyId } from "./keys.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Global keybinding registry.
|
|
4
|
+
* Downstream packages can add keybindings via declaration merging.
|
|
5
|
+
*/
|
|
6
|
+
export interface Keybindings {
|
|
7
|
+
"tui.editor.cursorUp": true;
|
|
8
|
+
"tui.editor.cursorDown": true;
|
|
9
|
+
"tui.editor.cursorLeft": true;
|
|
10
|
+
"tui.editor.cursorRight": true;
|
|
11
|
+
"tui.editor.cursorWordLeft": true;
|
|
12
|
+
"tui.editor.cursorWordRight": true;
|
|
13
|
+
"tui.editor.cursorLineStart": true;
|
|
14
|
+
"tui.editor.cursorLineEnd": true;
|
|
15
|
+
"tui.editor.jumpForward": true;
|
|
16
|
+
"tui.editor.jumpBackward": true;
|
|
17
|
+
"tui.editor.pageUp": true;
|
|
18
|
+
"tui.editor.pageDown": true;
|
|
19
|
+
"tui.editor.deleteCharBackward": true;
|
|
20
|
+
"tui.editor.deleteCharForward": true;
|
|
21
|
+
"tui.editor.deleteWordBackward": true;
|
|
22
|
+
"tui.editor.deleteWordForward": true;
|
|
23
|
+
"tui.editor.deleteToLineStart": true;
|
|
24
|
+
"tui.editor.deleteToLineEnd": true;
|
|
25
|
+
"tui.editor.yank": true;
|
|
26
|
+
"tui.editor.yankPop": true;
|
|
27
|
+
"tui.editor.undo": true;
|
|
28
|
+
"tui.input.newLine": true;
|
|
29
|
+
"tui.input.submit": true;
|
|
30
|
+
"tui.input.tab": true;
|
|
31
|
+
"tui.input.copy": true;
|
|
32
|
+
"tui.select.up": true;
|
|
33
|
+
"tui.select.down": true;
|
|
34
|
+
"tui.select.pageUp": true;
|
|
35
|
+
"tui.select.pageDown": true;
|
|
36
|
+
"tui.select.confirm": true;
|
|
37
|
+
"tui.select.cancel": true;
|
|
38
|
+
}
|
|
39
|
+
export type Keybinding = keyof Keybindings;
|
|
40
|
+
export interface KeybindingDefinition {
|
|
41
|
+
defaultKeys: KeyId | KeyId[];
|
|
42
|
+
description?: string;
|
|
43
|
+
}
|
|
44
|
+
export type KeybindingDefinitions = Record<string, KeybindingDefinition>;
|
|
45
|
+
export type KeybindingsConfig = Record<string, KeyId | KeyId[] | undefined>;
|
|
46
|
+
export declare const TUI_KEYBINDINGS: {
|
|
47
|
+
readonly "tui.editor.cursorUp": {
|
|
48
|
+
readonly defaultKeys: "up";
|
|
49
|
+
readonly description: "Move cursor up";
|
|
50
|
+
};
|
|
51
|
+
readonly "tui.editor.cursorDown": {
|
|
52
|
+
readonly defaultKeys: "down";
|
|
53
|
+
readonly description: "Move cursor down";
|
|
54
|
+
};
|
|
55
|
+
readonly "tui.editor.cursorLeft": {
|
|
56
|
+
readonly defaultKeys: ["left", "ctrl+b"];
|
|
57
|
+
readonly description: "Move cursor left";
|
|
58
|
+
};
|
|
59
|
+
readonly "tui.editor.cursorRight": {
|
|
60
|
+
readonly defaultKeys: ["right", "ctrl+f"];
|
|
61
|
+
readonly description: "Move cursor right";
|
|
62
|
+
};
|
|
63
|
+
readonly "tui.editor.cursorWordLeft": {
|
|
64
|
+
readonly defaultKeys: ["alt+left", "ctrl+left", "alt+b"];
|
|
65
|
+
readonly description: "Move cursor word left";
|
|
66
|
+
};
|
|
67
|
+
readonly "tui.editor.cursorWordRight": {
|
|
68
|
+
readonly defaultKeys: ["alt+right", "ctrl+right", "alt+f"];
|
|
69
|
+
readonly description: "Move cursor word right";
|
|
70
|
+
};
|
|
71
|
+
readonly "tui.editor.cursorLineStart": {
|
|
72
|
+
readonly defaultKeys: ["home", "ctrl+a"];
|
|
73
|
+
readonly description: "Move to line start";
|
|
74
|
+
};
|
|
75
|
+
readonly "tui.editor.cursorLineEnd": {
|
|
76
|
+
readonly defaultKeys: ["end", "ctrl+e"];
|
|
77
|
+
readonly description: "Move to line end";
|
|
78
|
+
};
|
|
79
|
+
readonly "tui.editor.jumpForward": {
|
|
80
|
+
readonly defaultKeys: "ctrl+]";
|
|
81
|
+
readonly description: "Jump forward to character";
|
|
82
|
+
};
|
|
83
|
+
readonly "tui.editor.jumpBackward": {
|
|
84
|
+
readonly defaultKeys: "ctrl+alt+]";
|
|
85
|
+
readonly description: "Jump backward to character";
|
|
86
|
+
};
|
|
87
|
+
readonly "tui.editor.pageUp": {
|
|
88
|
+
readonly defaultKeys: "pageUp";
|
|
89
|
+
readonly description: "Page up";
|
|
90
|
+
};
|
|
91
|
+
readonly "tui.editor.pageDown": {
|
|
92
|
+
readonly defaultKeys: "pageDown";
|
|
93
|
+
readonly description: "Page down";
|
|
94
|
+
};
|
|
95
|
+
readonly "tui.editor.deleteCharBackward": {
|
|
96
|
+
readonly defaultKeys: "backspace";
|
|
97
|
+
readonly description: "Delete character backward";
|
|
98
|
+
};
|
|
99
|
+
readonly "tui.editor.deleteCharForward": {
|
|
100
|
+
readonly defaultKeys: ["delete", "ctrl+d"];
|
|
101
|
+
readonly description: "Delete character forward";
|
|
102
|
+
};
|
|
103
|
+
readonly "tui.editor.deleteWordBackward": {
|
|
104
|
+
readonly defaultKeys: ["ctrl+w", "alt+backspace"];
|
|
105
|
+
readonly description: "Delete word backward";
|
|
106
|
+
};
|
|
107
|
+
readonly "tui.editor.deleteWordForward": {
|
|
108
|
+
readonly defaultKeys: ["alt+d", "alt+delete"];
|
|
109
|
+
readonly description: "Delete word forward";
|
|
110
|
+
};
|
|
111
|
+
readonly "tui.editor.deleteToLineStart": {
|
|
112
|
+
readonly defaultKeys: "ctrl+u";
|
|
113
|
+
readonly description: "Delete to line start";
|
|
114
|
+
};
|
|
115
|
+
readonly "tui.editor.deleteToLineEnd": {
|
|
116
|
+
readonly defaultKeys: "ctrl+k";
|
|
117
|
+
readonly description: "Delete to line end";
|
|
118
|
+
};
|
|
119
|
+
readonly "tui.editor.yank": {
|
|
120
|
+
readonly defaultKeys: "ctrl+y";
|
|
121
|
+
readonly description: "Yank";
|
|
122
|
+
};
|
|
123
|
+
readonly "tui.editor.yankPop": {
|
|
124
|
+
readonly defaultKeys: "alt+y";
|
|
125
|
+
readonly description: "Yank pop";
|
|
126
|
+
};
|
|
127
|
+
readonly "tui.editor.undo": {
|
|
128
|
+
readonly defaultKeys: "ctrl+-";
|
|
129
|
+
readonly description: "Undo";
|
|
130
|
+
};
|
|
131
|
+
readonly "tui.input.newLine": {
|
|
132
|
+
readonly defaultKeys: "shift+enter";
|
|
133
|
+
readonly description: "Insert newline";
|
|
134
|
+
};
|
|
135
|
+
readonly "tui.input.submit": {
|
|
136
|
+
readonly defaultKeys: "enter";
|
|
137
|
+
readonly description: "Submit input";
|
|
138
|
+
};
|
|
139
|
+
readonly "tui.input.tab": {
|
|
140
|
+
readonly defaultKeys: "tab";
|
|
141
|
+
readonly description: "Tab / autocomplete";
|
|
142
|
+
};
|
|
143
|
+
readonly "tui.input.copy": {
|
|
144
|
+
readonly defaultKeys: "ctrl+c";
|
|
145
|
+
readonly description: "Copy selection";
|
|
146
|
+
};
|
|
147
|
+
readonly "tui.select.up": {
|
|
148
|
+
readonly defaultKeys: "up";
|
|
149
|
+
readonly description: "Move selection up";
|
|
150
|
+
};
|
|
151
|
+
readonly "tui.select.down": {
|
|
152
|
+
readonly defaultKeys: "down";
|
|
153
|
+
readonly description: "Move selection down";
|
|
154
|
+
};
|
|
155
|
+
readonly "tui.select.pageUp": {
|
|
156
|
+
readonly defaultKeys: "pageUp";
|
|
157
|
+
readonly description: "Selection page up";
|
|
158
|
+
};
|
|
159
|
+
readonly "tui.select.pageDown": {
|
|
160
|
+
readonly defaultKeys: "pageDown";
|
|
161
|
+
readonly description: "Selection page down";
|
|
162
|
+
};
|
|
163
|
+
readonly "tui.select.confirm": {
|
|
164
|
+
readonly defaultKeys: "enter";
|
|
165
|
+
readonly description: "Confirm selection";
|
|
166
|
+
};
|
|
167
|
+
readonly "tui.select.cancel": {
|
|
168
|
+
readonly defaultKeys: ["escape", "ctrl+c"];
|
|
169
|
+
readonly description: "Cancel selection";
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
export interface KeybindingConflict {
|
|
173
|
+
key: KeyId;
|
|
174
|
+
keybindings: string[];
|
|
175
|
+
}
|
|
176
|
+
export declare class KeybindingsManager {
|
|
177
|
+
private definitions;
|
|
178
|
+
private userBindings;
|
|
179
|
+
private keysById;
|
|
180
|
+
private conflicts;
|
|
181
|
+
constructor(definitions: KeybindingDefinitions, userBindings?: KeybindingsConfig);
|
|
182
|
+
private rebuild;
|
|
183
|
+
matches(data: string, keybinding: Keybinding): boolean;
|
|
184
|
+
getKeys(keybinding: Keybinding): KeyId[];
|
|
185
|
+
getDefinition(keybinding: Keybinding): KeybindingDefinition;
|
|
186
|
+
getConflicts(): KeybindingConflict[];
|
|
187
|
+
setUserBindings(userBindings: KeybindingsConfig): void;
|
|
188
|
+
getUserBindings(): KeybindingsConfig;
|
|
189
|
+
getResolvedBindings(): KeybindingsConfig;
|
|
190
|
+
}
|
|
191
|
+
export declare function setKeybindings(keybindings: KeybindingsManager): void;
|
|
192
|
+
export declare function getKeybindings(): KeybindingsManager;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var u=Object.defineProperty;var n=(s,e)=>u(s,"name",{value:e,configurable:!0});import{matchesKey as a}from"./keys.js";const l={"tui.editor.cursorUp":{defaultKeys:"up",description:"Move cursor up"},"tui.editor.cursorDown":{defaultKeys:"down",description:"Move cursor down"},"tui.editor.cursorLeft":{defaultKeys:["left","ctrl+b"],description:"Move cursor left"},"tui.editor.cursorRight":{defaultKeys:["right","ctrl+f"],description:"Move cursor right"},"tui.editor.cursorWordLeft":{defaultKeys:["alt+left","ctrl+left","alt+b"],description:"Move cursor word left"},"tui.editor.cursorWordRight":{defaultKeys:["alt+right","ctrl+right","alt+f"],description:"Move cursor word right"},"tui.editor.cursorLineStart":{defaultKeys:["home","ctrl+a"],description:"Move to line start"},"tui.editor.cursorLineEnd":{defaultKeys:["end","ctrl+e"],description:"Move to line end"},"tui.editor.jumpForward":{defaultKeys:"ctrl+]",description:"Jump forward to character"},"tui.editor.jumpBackward":{defaultKeys:"ctrl+alt+]",description:"Jump backward to character"},"tui.editor.pageUp":{defaultKeys:"pageUp",description:"Page up"},"tui.editor.pageDown":{defaultKeys:"pageDown",description:"Page down"},"tui.editor.deleteCharBackward":{defaultKeys:"backspace",description:"Delete character backward"},"tui.editor.deleteCharForward":{defaultKeys:["delete","ctrl+d"],description:"Delete character forward"},"tui.editor.deleteWordBackward":{defaultKeys:["ctrl+w","alt+backspace"],description:"Delete word backward"},"tui.editor.deleteWordForward":{defaultKeys:["alt+d","alt+delete"],description:"Delete word forward"},"tui.editor.deleteToLineStart":{defaultKeys:"ctrl+u",description:"Delete to line start"},"tui.editor.deleteToLineEnd":{defaultKeys:"ctrl+k",description:"Delete to line end"},"tui.editor.yank":{defaultKeys:"ctrl+y",description:"Yank"},"tui.editor.yankPop":{defaultKeys:"alt+y",description:"Yank pop"},"tui.editor.undo":{defaultKeys:"ctrl+-",description:"Undo"},"tui.input.newLine":{defaultKeys:"shift+enter",description:"Insert newline"},"tui.input.submit":{defaultKeys:"enter",description:"Submit input"},"tui.input.tab":{defaultKeys:"tab",description:"Tab / autocomplete"},"tui.input.copy":{defaultKeys:"ctrl+c",description:"Copy selection"},"tui.select.up":{defaultKeys:"up",description:"Move selection up"},"tui.select.down":{defaultKeys:"down",description:"Move selection down"},"tui.select.pageUp":{defaultKeys:"pageUp",description:"Selection page up"},"tui.select.pageDown":{defaultKeys:"pageDown",description:"Selection page down"},"tui.select.confirm":{defaultKeys:"enter",description:"Confirm selection"},"tui.select.cancel":{defaultKeys:["escape","ctrl+c"],description:"Cancel selection"}};function c(s){if(s===void 0)return[];const e=Array.isArray(s)?s:[s],t=new Set,i=[];for(const r of e)t.has(r)||(t.add(r),i.push(r));return i}n(c,"normalizeKeys");class f{static{n(this,"KeybindingsManager")}definitions;userBindings;keysById=new Map;conflicts=[];constructor(e,t={}){this.definitions=e,this.userBindings=t,this.rebuild()}rebuild(){this.keysById.clear(),this.conflicts=[];const e=new Map;for(const[t,i]of Object.entries(this.userBindings))if(t in this.definitions)for(const r of c(i)){const o=e.get(r)??new Set;o.add(t),e.set(r,o)}for(const[t,i]of e)i.size>1&&this.conflicts.push({key:t,keybindings:[...i]});for(const[t,i]of Object.entries(this.definitions)){const r=this.userBindings[t],o=c(r===void 0?i.defaultKeys:r);this.keysById.set(t,o)}}matches(e,t){const i=this.keysById.get(t)??[];for(const r of i)if(a(e,r))return!0;return!1}getKeys(e){return[...this.keysById.get(e)??[]]}getDefinition(e){return this.definitions[e]}getConflicts(){return this.conflicts.map(e=>({...e,keybindings:[...e.keybindings]}))}setUserBindings(e){this.userBindings=e,this.rebuild()}getUserBindings(){return{...this.userBindings}}getResolvedBindings(){const e={};for(const t of Object.keys(this.definitions)){const i=this.keysById.get(t)??[];e[t]=i.length===1?i[0]:[...i]}return e}}let d=null;function g(s){d=s}n(g,"setKeybindings");function h(){return d||(d=new f(l)),d}n(h,"getKeybindings");export{f as KeybindingsManager,l as TUI_KEYBINDINGS,h as getKeybindings,g as setKeybindings};
|