escape confirmation on create issue page
This commit is contained in:
parent
dcc2bbaa82
commit
759954f328
|
|
@ -78,6 +78,7 @@ async function bootstrap() {
|
|||
title: '',
|
||||
body: '',
|
||||
activeField: 'title',
|
||||
cursor: 0
|
||||
},
|
||||
addCommentForm: {
|
||||
body: '',
|
||||
|
|
@ -86,6 +87,7 @@ async function bootstrap() {
|
|||
title: '',
|
||||
body: '',
|
||||
activeField: 'title',
|
||||
cursor: 0
|
||||
},
|
||||
addTimeForm: {
|
||||
timeInput: '',
|
||||
|
|
|
|||
401
src/tui.ts
401
src/tui.ts
|
|
@ -435,6 +435,8 @@ export class TuiEngine {
|
|||
this.handleDetailsKeypress(str, key);
|
||||
} else if (this.state.screen === 'create-issue') {
|
||||
this.handleCreateIssueKeypress(str, key);
|
||||
} else if (this.state.screen === 'confirm-cancel-create') {
|
||||
this.handleConfirmCancelCreateKeypress(str, key);
|
||||
} else if (this.state.screen === 'add-comment') {
|
||||
this.handleAddCommentKeypress(str, key);
|
||||
} else if (this.state.screen === 'edit-issue') {
|
||||
|
|
@ -883,6 +885,7 @@ export class TuiEngine {
|
|||
this.state.createIssueForm.title = '';
|
||||
this.state.createIssueForm.body = '';
|
||||
this.state.createIssueForm.activeField = 'title';
|
||||
this.state.createIssueForm.cursor = this.state.createIssueForm.title.length;
|
||||
this.render();
|
||||
return;
|
||||
}
|
||||
|
|
@ -931,6 +934,32 @@ export class TuiEngine {
|
|||
* Key handling for detail screen scrolling
|
||||
*/
|
||||
private handleDetailsKeypress(str: string, key: any) {
|
||||
if (key && key.name === 'tab') {
|
||||
this.state.focusedPane = this.state.focusedPane === 'settings' ? 'list' : 'settings';
|
||||
this.render();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.state.focusedPane === 'settings') {
|
||||
if ((key && key.name === 'return') || str === '\r' || str === '\n') {
|
||||
const intervals = [0, 15, 30, 60, 300];
|
||||
const currentIdx = intervals.indexOf(this.state.autoRefreshInterval || 0);
|
||||
this.state.autoRefreshInterval = intervals[(currentIdx + 1) % intervals.length];
|
||||
this.state.config.autoRefreshInterval = this.state.autoRefreshInterval;
|
||||
this.restartAutoRefresh();
|
||||
saveGlobalConfig(this.state.config);
|
||||
this.render();
|
||||
return;
|
||||
}
|
||||
if ((key && key.name === 'escape') || str === '\u001b') {
|
||||
this.state.focusedPane = 'list';
|
||||
this.render();
|
||||
return;
|
||||
}
|
||||
// Swallow other keys in settings mode
|
||||
return;
|
||||
}
|
||||
|
||||
if (key && key.name === 'up') {
|
||||
if (this.state.detailScrollOffset > 0) {
|
||||
this.state.detailScrollOffset--;
|
||||
|
|
@ -981,6 +1010,7 @@ export class TuiEngine {
|
|||
this.state.editIssueForm.title = this.state.selectedIssue.title;
|
||||
this.state.editIssueForm.body = this.state.selectedIssue.body;
|
||||
this.state.editIssueForm.activeField = 'title';
|
||||
this.state.editIssueForm.cursor = this.state.editIssueForm.title.length;
|
||||
this.state.error = null;
|
||||
this.render();
|
||||
}
|
||||
|
|
@ -1068,6 +1098,8 @@ export class TuiEngine {
|
|||
this.renderAddTimeScreen(cols, rows);
|
||||
} else if (this.state.screen === 'confirm-state-change') {
|
||||
this.renderConfirmStateChangeScreen(cols, rows);
|
||||
} else if (this.state.screen === 'confirm-cancel-create') {
|
||||
this.renderConfirmCancelCreateScreen(cols, rows);
|
||||
} else if (this.state.screen === 'animating-close') {
|
||||
this.renderAnimationScreen(cols, rows, GRAVESTONE_FRAMES);
|
||||
} else if (this.state.screen === 'animating-reopen') {
|
||||
|
|
@ -1568,7 +1600,7 @@ export class TuiEngine {
|
|||
|
||||
// Paginate/Scroll calculations
|
||||
const metaHeight = labels ? 3 : 2; // Meta 1, optionally Meta 2 (Labels), and Separator
|
||||
const displayHeight = rows - 5 - metaHeight; // Header: 1, Borders: 2, Meta lines, Help: 1, and -1 to avoid scrolling
|
||||
const displayHeight = rows - 7 - metaHeight; // Header: 1, Borders: 3, Meta, Settings: 1, Help: 1, and -1
|
||||
const maxScroll = Math.max(0, contentLines.length - displayHeight);
|
||||
|
||||
// Bounds check scroll offset
|
||||
|
|
@ -1589,6 +1621,22 @@ export class TuiEngine {
|
|||
}
|
||||
}
|
||||
|
||||
console.log(chalk.bold.hex('#4A90E2')('├' + '─'.repeat(cols - 2) + '┤'));
|
||||
|
||||
const isSettings = this.state.focusedPane === 'settings';
|
||||
let refreshStr = 'Off';
|
||||
if (this.state.autoRefreshInterval) {
|
||||
if (this.state.autoRefreshInterval >= 60) {
|
||||
refreshStr = `${this.state.autoRefreshInterval / 60}m`;
|
||||
} else {
|
||||
refreshStr = `${this.state.autoRefreshInterval}s`;
|
||||
}
|
||||
}
|
||||
const text = ` Auto-Refresh: ${refreshStr} `;
|
||||
const coloredText = isSettings ? chalk.bgHex('#2E4E7E').white.bold(text) : chalk.gray(` Auto-Refresh: `) + chalk.bold(refreshStr);
|
||||
const paddingLength = Math.max(0, cols - 2 - stripAnsi(text).length - 1);
|
||||
console.log(borderCh + ' ' + coloredText + ' '.repeat(paddingLength) + borderCh);
|
||||
|
||||
console.log(chalk.bold.hex('#4A90E2')('└' + '─'.repeat(cols - 2) + '┘'));
|
||||
|
||||
// Footer Scroll percentage
|
||||
|
|
@ -1599,7 +1647,10 @@ export class TuiEngine {
|
|||
}
|
||||
|
||||
const actionKey = issue.state === 'open' ? 'Close' : 'Reopen';
|
||||
const helpLine = chalk.gray(` [?] Help [Esc/Backspace] Back to List [C] Add Comment [A] Assign [E] Edit [T] Add Time [X] ${actionKey} [R] Reload [O] Settings ${scrollHelp}`);
|
||||
let helpLine = chalk.gray(` [?] Help [Esc/Backspace] Back to List [C] Add Comment [A] Assign [E] Edit [T] Add Time [X] ${actionKey} [R] Reload [Tab] Menu ${scrollHelp}`);
|
||||
if (isSettings) {
|
||||
helpLine = chalk.gray(` [?] Help [Tab] Back to Details [Enter] Toggle Auto-Refresh [Esc] Quit menu`);
|
||||
}
|
||||
process.stdout.write(helpLine);
|
||||
}
|
||||
|
||||
|
|
@ -1708,14 +1759,30 @@ export class TuiEngine {
|
|||
// Title Field
|
||||
let titleLabel = ' Title: ';
|
||||
let titleVisible = form.title;
|
||||
if (titleVisible.length > cols - 13) {
|
||||
titleVisible = titleVisible.substring(titleVisible.length - (cols - 13));
|
||||
}
|
||||
let titleContent = titleVisible.padEnd(cols - 12);
|
||||
let titleContent = '';
|
||||
|
||||
if (form.activeField === 'title') {
|
||||
titleLabel = chalk.yellow(' Title: ');
|
||||
titleContent = chalk.inverse(titleVisible + ' ') + ' '.repeat(Math.max(0, cols - 13 - titleVisible.length));
|
||||
const c = Math.min(form.cursor || 0, form.title.length);
|
||||
|
||||
let startIdx = 0;
|
||||
if (c > cols - 13) {
|
||||
startIdx = c - (cols - 13) + 1;
|
||||
}
|
||||
|
||||
const visTitle = form.title.substring(startIdx);
|
||||
const visCursor = c - startIdx;
|
||||
|
||||
const visBefore = visTitle.substring(0, visCursor);
|
||||
const visChar = visCursor < visTitle.length ? visTitle[visCursor] : ' ';
|
||||
const visAfter = visTitle.substring(visCursor + 1).padEnd(Math.max(0, cols - 13 - visBefore.length - 1), ' ').substring(0, Math.max(0, cols - 13 - visBefore.length - 1));
|
||||
|
||||
titleContent = visBefore + chalk.inverse(visChar) + visAfter;
|
||||
} else {
|
||||
titleVisible = titleVisible.length > cols - 13 ? titleVisible.substring(titleVisible.length - (cols - 13)) : titleVisible;
|
||||
titleContent = titleVisible.padEnd(cols - 12);
|
||||
}
|
||||
|
||||
console.log(borderCh + titleLabel + titleContent + borderCh);
|
||||
console.log(chalk.bold.hex('#4A90E2')('├' + '─'.repeat(cols - 2) + '┤'));
|
||||
|
||||
|
|
@ -1730,10 +1797,29 @@ export class TuiEngine {
|
|||
// Body Content (multiline)
|
||||
const errorOffset = this.state.error ? 2 : 0;
|
||||
const bodyRows = rows - 10 - errorOffset; // available space for body
|
||||
const lines = form.body.split('\n');
|
||||
|
||||
// Pagination for body if it gets too long
|
||||
const startLine = Math.max(0, lines.length - bodyRows);
|
||||
const lines = form.body.split('\n');
|
||||
let cursorLine = 0;
|
||||
let cursorCol = 0;
|
||||
let remaining = Math.min(form.cursor || 0, form.body.length);
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (remaining <= lines[i].length) {
|
||||
cursorLine = i;
|
||||
cursorCol = remaining;
|
||||
break;
|
||||
}
|
||||
remaining -= lines[i].length + 1;
|
||||
}
|
||||
|
||||
let startLine = Math.max(0, lines.length - bodyRows);
|
||||
if (form.activeField === 'body') {
|
||||
if (cursorLine < startLine) {
|
||||
startLine = cursorLine;
|
||||
} else if (cursorLine >= startLine + bodyRows) {
|
||||
startLine = cursorLine - bodyRows + 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < bodyRows; i++) {
|
||||
const lineIdx = startLine + i;
|
||||
|
|
@ -1742,18 +1828,34 @@ export class TuiEngine {
|
|||
lineContent = lines[lineIdx];
|
||||
}
|
||||
|
||||
let visLine = lineContent;
|
||||
if (visLine.length > cols - 5) {
|
||||
visLine = visLine.substring(visLine.length - (cols - 5));
|
||||
}
|
||||
if (form.activeField === 'body' && lineIdx === cursorLine) {
|
||||
let startCol = 0;
|
||||
if (cursorCol > cols - 6) {
|
||||
startCol = cursorCol - (cols - 6) + 1;
|
||||
}
|
||||
|
||||
if (form.activeField === 'body' && lineIdx === lines.length - 1) {
|
||||
visLine = visLine + chalk.inverse(' ') + ' '.repeat(Math.max(0, cols - 5 - stripAnsi(visLine).length));
|
||||
const visLineStr = lineContent.substring(startCol);
|
||||
const visCursorCol = cursorCol - startCol;
|
||||
|
||||
const before = visLineStr.substring(0, visCursorCol);
|
||||
const char = visCursorCol < visLineStr.length ? visLineStr[visCursorCol] : ' ';
|
||||
const after = visLineStr.substring(visCursorCol + 1);
|
||||
|
||||
let visLine = before + chalk.inverse(char) + after;
|
||||
const plainLen = stripAnsi(visLine).length;
|
||||
if (plainLen < cols - 4) {
|
||||
visLine += ' '.repeat(cols - 4 - plainLen);
|
||||
}
|
||||
|
||||
console.log(borderCh + ' ' + visLine + ' ' + borderCh);
|
||||
} else {
|
||||
visLine = visLine.padEnd(cols - 4);
|
||||
let visLineStr = lineContent;
|
||||
if (visLineStr.length > cols - 5) {
|
||||
visLineStr = visLineStr.substring(visLineStr.length - (cols - 5));
|
||||
}
|
||||
visLineStr = visLineStr.padEnd(cols - 4);
|
||||
console.log(borderCh + ' ' + visLineStr + ' ' + borderCh);
|
||||
}
|
||||
|
||||
console.log(borderCh + ' ' + visLine + ' ' + borderCh);
|
||||
}
|
||||
|
||||
console.log(chalk.bold.hex('#4A90E2')('└' + '─'.repeat(cols - 2) + '┘'));
|
||||
|
|
@ -1778,7 +1880,7 @@ export class TuiEngine {
|
|||
*/
|
||||
private async handleCreateIssueKeypress(str: string, key: any) {
|
||||
if (key && key.name === 'escape') {
|
||||
this.state.screen = 'list';
|
||||
this.state.screen = 'confirm-cancel-create';
|
||||
this.state.error = null;
|
||||
this.render();
|
||||
return;
|
||||
|
|
@ -1813,6 +1915,7 @@ export class TuiEngine {
|
|||
|
||||
if (key && key.name === 'tab') {
|
||||
this.state.createIssueForm.activeField = this.state.createIssueForm.activeField === 'title' ? 'body' : 'title';
|
||||
this.state.createIssueForm.cursor = this.state.createIssueForm[this.state.createIssueForm.activeField].length;
|
||||
this.render();
|
||||
return;
|
||||
}
|
||||
|
|
@ -1820,10 +1923,59 @@ export class TuiEngine {
|
|||
// Text input handling
|
||||
const activeField = this.state.createIssueForm.activeField;
|
||||
let val = this.state.createIssueForm[activeField];
|
||||
let cursor = this.state.createIssueForm.cursor;
|
||||
if (cursor === undefined || cursor > val.length) cursor = val.length;
|
||||
|
||||
if (key && key.name === 'backspace') {
|
||||
if (val.length > 0) {
|
||||
this.state.createIssueForm[activeField] = val.slice(0, -1);
|
||||
if (key && key.name === 'left') {
|
||||
this.state.createIssueForm.cursor = Math.max(0, cursor - 1);
|
||||
this.render();
|
||||
return;
|
||||
}
|
||||
|
||||
if (key && key.name === 'right') {
|
||||
this.state.createIssueForm.cursor = Math.min(val.length, cursor + 1);
|
||||
this.render();
|
||||
return;
|
||||
}
|
||||
|
||||
if (key && (key.name === 'up' || key.name === 'down') && activeField === 'body') {
|
||||
const lines = val.split('
|
||||
');
|
||||
let lineIdx = 0, col = 0, count = 0;
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (count + lines[i].length >= cursor) {
|
||||
lineIdx = i;
|
||||
col = cursor - count;
|
||||
break;
|
||||
}
|
||||
count += lines[i].length + 1;
|
||||
}
|
||||
|
||||
if (key.name === 'up' && lineIdx > 0) {
|
||||
const prevLine = lines[lineIdx - 1];
|
||||
const newCol = Math.min(col, prevLine.length);
|
||||
let newCursor = 0;
|
||||
for (let i = 0; i < lineIdx - 1; i++) newCursor += lines[i].length + 1;
|
||||
this.state.createIssueForm.cursor = newCursor + newCol;
|
||||
this.render();
|
||||
} else if (key.name === 'down' && lineIdx < lines.length - 1) {
|
||||
const nextLine = lines[lineIdx + 1];
|
||||
const newCol = Math.min(col, nextLine.length);
|
||||
let newCursor = 0;
|
||||
for (let i = 0; i <= lineIdx; i++) newCursor += lines[i].length + 1;
|
||||
this.state.createIssueForm.cursor = newCursor + newCol;
|
||||
this.render();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (key && (key.name === 'backspace' || key.name === 'delete')) {
|
||||
if (key.name === 'backspace' && cursor > 0) {
|
||||
this.state.createIssueForm[activeField] = val.slice(0, cursor - 1) + val.slice(cursor);
|
||||
this.state.createIssueForm.cursor = cursor - 1;
|
||||
this.render();
|
||||
} else if (key.name === 'delete' && cursor < val.length) {
|
||||
this.state.createIssueForm[activeField] = val.slice(0, cursor) + val.slice(cursor + 1);
|
||||
this.render();
|
||||
}
|
||||
return;
|
||||
|
|
@ -1831,11 +1983,13 @@ export class TuiEngine {
|
|||
|
||||
if (key && key.name === 'return') {
|
||||
if (activeField === 'body') {
|
||||
this.state.createIssueForm.body += '\n';
|
||||
this.state.createIssueForm.body = val.slice(0, cursor) + '
|
||||
' + val.slice(cursor);
|
||||
this.state.createIssueForm.cursor = cursor + 1;
|
||||
this.render();
|
||||
} else {
|
||||
// In title, return switches to body
|
||||
this.state.createIssueForm.activeField = 'body';
|
||||
this.state.createIssueForm.cursor = this.state.createIssueForm.body.length;
|
||||
this.render();
|
||||
}
|
||||
return;
|
||||
|
|
@ -1843,7 +1997,8 @@ export class TuiEngine {
|
|||
|
||||
if (str && str.length === 1 && !key.ctrl && !key.meta) {
|
||||
this.state.error = null;
|
||||
this.state.createIssueForm[activeField] += str;
|
||||
this.state.createIssueForm[activeField] = val.slice(0, cursor) + str + val.slice(cursor);
|
||||
this.state.createIssueForm.cursor = cursor + 1;
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
|
@ -2000,14 +2155,30 @@ export class TuiEngine {
|
|||
// Title Field
|
||||
let titleLabel = ' Title: ';
|
||||
let titleVisible = form.title;
|
||||
if (titleVisible.length > cols - 13) {
|
||||
titleVisible = titleVisible.substring(titleVisible.length - (cols - 13));
|
||||
}
|
||||
let titleContent = titleVisible.padEnd(cols - 12);
|
||||
let titleContent = '';
|
||||
|
||||
if (form.activeField === 'title') {
|
||||
titleLabel = chalk.yellow(' Title: ');
|
||||
titleContent = chalk.inverse(titleVisible + ' ') + ' '.repeat(Math.max(0, cols - 13 - titleVisible.length));
|
||||
const c = Math.min(form.cursor || 0, form.title.length);
|
||||
|
||||
let startIdx = 0;
|
||||
if (c > cols - 13) {
|
||||
startIdx = c - (cols - 13) + 1;
|
||||
}
|
||||
|
||||
const visTitle = form.title.substring(startIdx);
|
||||
const visCursor = c - startIdx;
|
||||
|
||||
const visBefore = visTitle.substring(0, visCursor);
|
||||
const visChar = visCursor < visTitle.length ? visTitle[visCursor] : ' ';
|
||||
const visAfter = visTitle.substring(visCursor + 1).padEnd(Math.max(0, cols - 13 - visBefore.length - 1), ' ').substring(0, Math.max(0, cols - 13 - visBefore.length - 1));
|
||||
|
||||
titleContent = visBefore + chalk.inverse(visChar) + visAfter;
|
||||
} else {
|
||||
titleVisible = titleVisible.length > cols - 13 ? titleVisible.substring(titleVisible.length - (cols - 13)) : titleVisible;
|
||||
titleContent = titleVisible.padEnd(cols - 12);
|
||||
}
|
||||
|
||||
console.log(borderCh + titleLabel + titleContent + borderCh);
|
||||
console.log(chalk.bold.hex('#4A90E2')('├' + '─'.repeat(cols - 2) + '┤'));
|
||||
|
||||
|
|
@ -2022,10 +2193,29 @@ export class TuiEngine {
|
|||
// Body Content (multiline)
|
||||
const errorOffset = this.state.error ? 2 : 0;
|
||||
const bodyRows = rows - 10 - errorOffset; // available space for body
|
||||
const lines = form.body.split('\n');
|
||||
|
||||
// Pagination for body if it gets too long
|
||||
const startLine = Math.max(0, lines.length - bodyRows);
|
||||
const lines = form.body.split('\n');
|
||||
let cursorLine = 0;
|
||||
let cursorCol = 0;
|
||||
let remaining = Math.min(form.cursor || 0, form.body.length);
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (remaining <= lines[i].length) {
|
||||
cursorLine = i;
|
||||
cursorCol = remaining;
|
||||
break;
|
||||
}
|
||||
remaining -= lines[i].length + 1;
|
||||
}
|
||||
|
||||
let startLine = Math.max(0, lines.length - bodyRows);
|
||||
if (form.activeField === 'body') {
|
||||
if (cursorLine < startLine) {
|
||||
startLine = cursorLine;
|
||||
} else if (cursorLine >= startLine + bodyRows) {
|
||||
startLine = cursorLine - bodyRows + 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < bodyRows; i++) {
|
||||
const lineIdx = startLine + i;
|
||||
|
|
@ -2034,18 +2224,34 @@ export class TuiEngine {
|
|||
lineContent = lines[lineIdx];
|
||||
}
|
||||
|
||||
let visLine = lineContent;
|
||||
if (visLine.length > cols - 5) {
|
||||
visLine = visLine.substring(visLine.length - (cols - 5));
|
||||
}
|
||||
if (form.activeField === 'body' && lineIdx === cursorLine) {
|
||||
let startCol = 0;
|
||||
if (cursorCol > cols - 6) {
|
||||
startCol = cursorCol - (cols - 6) + 1;
|
||||
}
|
||||
|
||||
if (form.activeField === 'body' && lineIdx === lines.length - 1) {
|
||||
visLine = visLine + chalk.inverse(' ') + ' '.repeat(Math.max(0, cols - 5 - stripAnsi(visLine).length));
|
||||
const visLineStr = lineContent.substring(startCol);
|
||||
const visCursorCol = cursorCol - startCol;
|
||||
|
||||
const before = visLineStr.substring(0, visCursorCol);
|
||||
const char = visCursorCol < visLineStr.length ? visLineStr[visCursorCol] : ' ';
|
||||
const after = visLineStr.substring(visCursorCol + 1);
|
||||
|
||||
let visLine = before + chalk.inverse(char) + after;
|
||||
const plainLen = stripAnsi(visLine).length;
|
||||
if (plainLen < cols - 4) {
|
||||
visLine += ' '.repeat(cols - 4 - plainLen);
|
||||
}
|
||||
|
||||
console.log(borderCh + ' ' + visLine + ' ' + borderCh);
|
||||
} else {
|
||||
visLine = visLine.padEnd(cols - 4);
|
||||
let visLineStr = lineContent;
|
||||
if (visLineStr.length > cols - 5) {
|
||||
visLineStr = visLineStr.substring(visLineStr.length - (cols - 5));
|
||||
}
|
||||
visLineStr = visLineStr.padEnd(cols - 4);
|
||||
console.log(borderCh + ' ' + visLineStr + ' ' + borderCh);
|
||||
}
|
||||
|
||||
console.log(borderCh + ' ' + visLine + ' ' + borderCh);
|
||||
}
|
||||
|
||||
console.log(chalk.bold.hex('#4A90E2')('└' + '─'.repeat(cols - 2) + '┘'));
|
||||
|
|
@ -2113,6 +2319,7 @@ export class TuiEngine {
|
|||
|
||||
if (key && key.name === 'tab') {
|
||||
this.state.editIssueForm.activeField = this.state.editIssueForm.activeField === 'title' ? 'body' : 'title';
|
||||
this.state.editIssueForm.cursor = this.state.editIssueForm[this.state.editIssueForm.activeField].length;
|
||||
this.render();
|
||||
return;
|
||||
}
|
||||
|
|
@ -2120,10 +2327,59 @@ export class TuiEngine {
|
|||
// Text input handling
|
||||
const activeField = this.state.editIssueForm.activeField;
|
||||
let val = this.state.editIssueForm[activeField];
|
||||
let cursor = this.state.editIssueForm.cursor;
|
||||
if (cursor === undefined || cursor > val.length) cursor = val.length;
|
||||
|
||||
if (key && key.name === 'backspace') {
|
||||
if (val.length > 0) {
|
||||
this.state.editIssueForm[activeField] = val.slice(0, -1);
|
||||
if (key && key.name === 'left') {
|
||||
this.state.editIssueForm.cursor = Math.max(0, cursor - 1);
|
||||
this.render();
|
||||
return;
|
||||
}
|
||||
|
||||
if (key && key.name === 'right') {
|
||||
this.state.editIssueForm.cursor = Math.min(val.length, cursor + 1);
|
||||
this.render();
|
||||
return;
|
||||
}
|
||||
|
||||
if (key && (key.name === 'up' || key.name === 'down') && activeField === 'body') {
|
||||
const lines = val.split('
|
||||
');
|
||||
let lineIdx = 0, col = 0, count = 0;
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (count + lines[i].length >= cursor) {
|
||||
lineIdx = i;
|
||||
col = cursor - count;
|
||||
break;
|
||||
}
|
||||
count += lines[i].length + 1;
|
||||
}
|
||||
|
||||
if (key.name === 'up' && lineIdx > 0) {
|
||||
const prevLine = lines[lineIdx - 1];
|
||||
const newCol = Math.min(col, prevLine.length);
|
||||
let newCursor = 0;
|
||||
for (let i = 0; i < lineIdx - 1; i++) newCursor += lines[i].length + 1;
|
||||
this.state.editIssueForm.cursor = newCursor + newCol;
|
||||
this.render();
|
||||
} else if (key.name === 'down' && lineIdx < lines.length - 1) {
|
||||
const nextLine = lines[lineIdx + 1];
|
||||
const newCol = Math.min(col, nextLine.length);
|
||||
let newCursor = 0;
|
||||
for (let i = 0; i <= lineIdx; i++) newCursor += lines[i].length + 1;
|
||||
this.state.editIssueForm.cursor = newCursor + newCol;
|
||||
this.render();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (key && (key.name === 'backspace' || key.name === 'delete')) {
|
||||
if (key.name === 'backspace' && cursor > 0) {
|
||||
this.state.editIssueForm[activeField] = val.slice(0, cursor - 1) + val.slice(cursor);
|
||||
this.state.editIssueForm.cursor = cursor - 1;
|
||||
this.render();
|
||||
} else if (key.name === 'delete' && cursor < val.length) {
|
||||
this.state.editIssueForm[activeField] = val.slice(0, cursor) + val.slice(cursor + 1);
|
||||
this.render();
|
||||
}
|
||||
return;
|
||||
|
|
@ -2131,11 +2387,13 @@ export class TuiEngine {
|
|||
|
||||
if (key && key.name === 'return') {
|
||||
if (activeField === 'body') {
|
||||
this.state.editIssueForm.body += '\n';
|
||||
this.state.editIssueForm.body = val.slice(0, cursor) + '
|
||||
' + val.slice(cursor);
|
||||
this.state.editIssueForm.cursor = cursor + 1;
|
||||
this.render();
|
||||
} else {
|
||||
// In title, return switches to body
|
||||
this.state.editIssueForm.activeField = 'body';
|
||||
this.state.editIssueForm.cursor = this.state.editIssueForm.body.length;
|
||||
this.render();
|
||||
}
|
||||
return;
|
||||
|
|
@ -2143,7 +2401,8 @@ export class TuiEngine {
|
|||
|
||||
if (str && str.length === 1 && !key.ctrl && !key.meta) {
|
||||
this.state.error = null;
|
||||
this.state.editIssueForm[activeField] += str;
|
||||
this.state.editIssueForm[activeField] = val.slice(0, cursor) + str + val.slice(cursor);
|
||||
this.state.editIssueForm.cursor = cursor + 1;
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
|
@ -2372,6 +2631,50 @@ export class TuiEngine {
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private renderConfirmCancelCreateScreen(cols: number, rows: number) {
|
||||
const borderCh = chalk.bold.hex('#4A90E2')('│');
|
||||
|
||||
const title = ' Confirm Cancel ';
|
||||
const leftLen = stripAnsi(title).length;
|
||||
let leftHeader = chalk.bold.hex('#4A90E2')(title);
|
||||
|
||||
console.log(leftHeader + ' '.repeat(Math.max(1, cols - leftLen - 1)));
|
||||
console.log(chalk.bold.hex('#4A90E2')('┌' + '─'.repeat(cols - 2) + '┐'));
|
||||
|
||||
const question = 'Are you sure you want to cancel creating this issue?';
|
||||
const promptPlain = ` ${question} [y/N] `;
|
||||
|
||||
const paddingRows = Math.floor((rows - 8) / 2);
|
||||
for (let i = 0; i < paddingRows; i++) console.log(borderCh + ' '.repeat(cols - 2) + borderCh);
|
||||
|
||||
const padContentLeft = Math.max(0, Math.floor((cols - 2 - promptPlain.length) / 2));
|
||||
const contentLine = (' '.repeat(padContentLeft) + chalk.yellow.bold(question) + ' [y/N] ').padEnd(cols - 2 + (chalk.yellow.bold(question).length - question.length));
|
||||
console.log(borderCh + contentLine + borderCh);
|
||||
|
||||
for (let i = 0; i < (rows - 8) - paddingRows; i++) console.log(borderCh + ' '.repeat(cols - 2) + borderCh);
|
||||
|
||||
console.log(chalk.bold.hex('#4A90E2')('└' + '─'.repeat(cols - 2) + '┘'));
|
||||
|
||||
const helpLinePlain = ' [y] Yes [n/Esc] No';
|
||||
process.stdout.write(chalk.gray(helpLinePlain));
|
||||
}
|
||||
|
||||
private async handleConfirmCancelCreateKeypress(str: string, key: any) {
|
||||
if ((key && (key.name === 'escape' || key.name === 'n')) || str === 'n' || str === 'N') {
|
||||
this.state.screen = 'create-issue';
|
||||
this.state.error = null;
|
||||
this.render();
|
||||
return;
|
||||
}
|
||||
|
||||
if (str === 'y' || str === 'Y') {
|
||||
this.state.screen = 'list';
|
||||
this.state.error = null;
|
||||
this.render();
|
||||
return;
|
||||
}
|
||||
}
|
||||
private renderSetAssigneesScreen(cols: number, rows: number) {
|
||||
const borderCh = chalk.bold.hex('#4A90E2')('│');
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ export interface CreateIssueForm {
|
|||
title: string;
|
||||
body: string;
|
||||
activeField: 'title' | 'body';
|
||||
cursor: number;
|
||||
}
|
||||
|
||||
export interface AddCommentForm {
|
||||
|
|
@ -67,6 +68,7 @@ export interface EditIssueForm {
|
|||
title: string;
|
||||
body: string;
|
||||
activeField: 'title' | 'body';
|
||||
cursor: number;
|
||||
}
|
||||
|
||||
export interface AddTimeForm {
|
||||
|
|
@ -81,7 +83,7 @@ export interface LabelForm {
|
|||
activeField: 'name' | 'color' | 'description' | 'exclusive';
|
||||
}
|
||||
|
||||
export type ScreenType = 'launch' | 'setup' | 'repo-picker' | 'list' | 'details' | 'create-issue' | 'add-comment' | 'edit-issue' | 'add-time' | 'confirm-state-change' | 'animating-close' | 'animating-reopen' | 'set-assignees' | 'labels-list' | 'create-label' | 'edit-label' | 'help';
|
||||
export type ScreenType = 'launch' | 'setup' | 'repo-picker' | 'list' | 'details' | 'create-issue' | 'add-comment' | 'edit-issue' | 'add-time' | 'confirm-state-change' | 'confirm-cancel-create' | 'animating-close' | 'animating-reopen' | 'set-assignees' | 'labels-list' | 'create-label' | 'edit-label' | 'help';
|
||||
|
||||
|
||||
export interface RepoItem {
|
||||
|
|
|
|||
Loading…
Reference in New Issue